2012-02-14 34 views
6

Yinelenen olaylarla ilgili soruların yaygın olduğunu biliyorum, ancak takvim uygulamalarıyla ilgili olanlar dışında yinelenen etkinlikler hakkında bu özel soruyu yanıtlayan birini bulamadım. En önemli fark, uygulamamızdaki olayların olması. Sadece bir takvim biçiminde değil, raporlarda ya da kendilerinde görülebilirler, ancak pek çok yönden çok benzer olsalar da, takvimlerle ilişkili bagajlar daha azdır.Yinelenen Olaylar, SQL Sorgu

Bir takvim uygulamasına benzer şekilde. Olaylar ya bir defaya mahsus olarak gerçekleşebilir ya da yinelenebilir. Her perşembe veya her ayın ilk Pazartesi günü, gelecekteki bazı önceden ayarlanan zamana kadar.

Olaylar, başlangıç ​​ve bitiş tarihleri ​​ile 'yineleme türü kimliği' içeren bir olay tablosunda depolanır. Eğer 'yineleme' türü 'Yok' ise, başlangıç ​​ve bitiş tarihleri ​​aynı olacaktır. Etkinlik tablosu, kimlik tipini tutan ayrı bir tabloya bir kimlik tutar, E.g. 'Toplantı' veya 'Haftalık rapor'

'Tekrarlama türleri' listesini içeren başka bir tablo var. 'Tekrarlama yok', 'Her Pazartesi', 'İlk Pazartesi günü' ve 'Son Cumartesi günü'.

Aramaları daha kolay hale getirmek için başka bir tablo, 1960'dan 2060'a kadar her tarihle ilgili bilgilerle birlikte, bir Pazartesi günü olup olmadığı ve ayın hangi pazartesi olduğu gibi bir tarih listesini içerir.

Bu

sağlayan bir arama gibi:
 
+-----------+---------------+-------------------+-----------+------------+-------------------------------+ 
| eventid | nameid  | lastname   | firstname | dt   | recurring      | 
+-----------+---------------+-------------------+-----------+------------+-------------------------------+ 
| 3291788 |  1728449 | smith    | zoe  | 2012-02-02 | First Thursday, every month | 
| 3291797 |  1765432 |     |   | 2012-02-05 | First Sunday, every month  | 
| 3291798 |  1730147 |     |   | 2012-02-05 | First Sunday, every month  | 
| 3291803 |  1790061 | Carpenter   | Richie | 2012-02-06 | Every Monday     | 
| 3291805 |  1790061 | Carpenter   | Richie | 2012-02-08 | Second Wednesday, every month | 
| 3291803 |  1790061 | Carpenter   | Richie | 2012-02-13 | Every Monday     | 
| 3291799 |  1790061 | Carpenter   | Richie | 2012-02-15 | Third Wednesday, every month | 
| 3291803 |  1790061 | Carpenter   | Richie | 2012-02-20 | Every Monday     | 

hiçbiri yinelenen olaylar daha basit bir sorgu kullanılabilir almak için:: gibi çıkış veren, düzenli etkinlikler bulmak için gerekli olan tam olarak ne

 
SELECT DISTINCT(e.eventid),n.nameid,n.firstname,n.lastname,d.dt,r.recurring 
FROM dates d 
LEFT JOIN recurringtypes r 
/* if event recurring every week E.g. 'Every Monday' */ 
ON (r.rectypeid BETWEEN 2 AND 8 AND r.day = d.dow) 
/* if event recurring every month E.g. 'First Monday, every month' */ 
OR ((r.rectypeid BETWEEN 9 AND 36) AND r.day = d.dow AND r.occurrence = d.occurrence) 
/* if event recurring every last week of month E.g. 'Last Monday, every month' */ 
OR (r.rectypeid >= 37 AND r.day = d.dow and r.islast = d.islast) 
LEFT JOIN events e on e.rectypeid = r.rectypeid 
LEFT JOIN eventtypes t ON e.eventtypeid = t.eventtypeid 
LEFT JOIN names n ON e.namesid = n.namesid 
WHERE (d.dt BETWEEN '2012/02/01' AND '2012/05/01') 
ORDER BY d.dt; 

 
SELECT n.nameid,n.lastname,n.firstname,e.firstdate,e.eventid,'No' as Recurring 
FROM events e 
LEFT JOIN names n ON n.names = e.namesid 
AND e.rectypeid <= 1 
AND e.firstdate BETWEEN '2012/02/01' AND '2012/05/01' 
AND e.eventid IS NOT NULL ORDER BY e.firstdate; 
Bu, ilk sorguya çok benzer bir çıktı verir, ancak, tarihler, tarih tablosundan ziyade olaylar tablosundan gelir.

Sorum şu: Bu sorguları, tarih sıralamasında yinelenen ve yinelenmeyen tüm olayları içeren bir liste oluşturmak için nasıl birleştirebilirim?


Bunlar tabloları ve onlardan kısaltılmış seçimleri, bazı sütunlar ve tüm indeksleri :) kısalık için kaldırıldı. 'İsimler' tablosu aynı nedenden dolayı dahil edilmemiştir.

 
CREATE TABLE events (
eventid int(11) NOT NULL AUTO_INCREMENT, 
eventtypeid int(11) DEFAULT '0', 
firstdate date DEFAULT '1960-01-01' COMMENT 'First event', 
lastdate date DEFAULT '1960-01-01' COMMENT 'Last event', 
rectypeid int(11) DEFAULT '1' 
); 
+---------+-------------+------------+------------+-----------+ 
| eventid | eventtypeid | firstdate | lastdate | rectypeid | 
+---------+-------------+------------+------------+-----------+ 
| 3291803 |   16 | 2012-02-03 | 2012-04-11 |   3 | 
| 3291797 |   8 | 2012-02-12 | 2012-02-22 |   9 | 
| 3291798 |   5 | 2012-02-12 | 2012-02-12 |   9 | 
| 3291788 |   8 | 2012-05-24 | 2015-01-16 |  13 | 
| 3291805 |   10 | 2012-01-04 | 2012-02-14 |  19 | 
| 3291799 |   16 | 2012-02-07 | 2012-10-24 |  26 | 
| 3291804 |   5 | 2012-02-03 | 2012-08-22 |  41 | 
+---------+-------------+------------+------------+-----------+ 
CREATE TABLE cmseventtypes (
eventtypeid int(11) NOT NULL AUTO_INCREMENT, 
eventtype varchar(50) DEFAULT '' COMMENT 'Event type AKA name' 
); 
+-------------+----------------------+ 
| eventtypeid | eventype    | 
+-------------+----------------------+ 
|   1 | Follow up meeting | 
|   2 | Reminder email due | 
|   3 | Monthly meeting  | 
|   4 | Weekly report  | 
|   5 | Golf practice  | 
+------------------------------------+ 
CREATE TABLE recurringtypes (
rectypeid int(11) NOT NULL AUTO_INCREMENT, 
recurring varchar(40) DEFAULT '', 
day tinyint(4) DEFAULT '0', 
occurrence tinyint(4) DEFAULT '0', 
islast tinyint(4) DEFAULT '0' 
); 
+-----------+---------------------------+------+------------+--------+ 
| rectypeid | recurring     | day | occurrence | islast | 
+-----------+---------------------------+------+------------+--------+ 
|   1 | No      | 0 |   0 |  0 | 
|   2 | Every Sunday    | 1 |   0 |  0 | 
|   3 | Every Monday    | 2 |   0 |  0 | 
|   4 | Every Tuesday    | 3 |   0 |  0 | 
|   5 | Every Wednesday   | 4 |   0 |  0 | 
|   6 | Every Thursday   | 5 |   0 |  0 | 
|   7 | Every Friday    | 6 |   0 |  0 | 
|   8 | Every Saturday   | 7 |   0 |  0 | 
|   9 | First Sunday, every month | 1 |   1 |  0 | 
|  10 | First Monday, every month | 2 |   1 |  0 | 
+-----------+---------------------------+------+------------+--------+ 
CREATE TABLE dates (
dt date NOT NULL COMMENT 'Date', 
daycount mediumint(9) NOT NULL DEFAULT '1', 
year smallint(6) NOT NULL DEFAULT '1970', 
month tinyint(4) NOT NULL DEFAULT '1', 
dom tinyint(4) NOT NULL DEFAULT '1', 
dow tinyint(4) NOT NULL DEFAULT '1', 
occurrence tinyint(4) NOT NULL DEFAULT '0', 
islast tinyint(1) NOT NULL DEFAULT '0' 
); 
+------------+----------+------+-------+-----+-----+------------+--------+ 
| dt   | daycount | year | month | dom | dow | occurrence | islast | 
+------------+----------+------+-------+-----+-----+------------+--------+ 
| 2012-02-02 | 734900 | 2012 |  2 | 2 | 5 |   1 |  0 | 
| 2012-02-03 | 734901 | 2012 |  2 | 3 | 6 |   1 |  0 | 
| 2012-02-04 | 734902 | 2012 |  2 | 4 | 7 |   1 |  0 | 
| 2012-02-05 | 734903 | 2012 |  2 | 5 | 1 |   1 |  0 | 
| 2012-02-06 | 734904 | 2012 |  2 | 6 | 2 |   1 |  0 | 
| 2012-02-07 | 734905 | 2012 |  2 | 7 | 3 |   1 |  0 | 
| 2012-02-08 | 734906 | 2012 |  2 | 8 | 4 |   2 |  0 | 
| 2012-02-09 | 734907 | 2012 |  2 | 9 | 5 |   2 |  0 | 
+------------+----------+------+-------+-----+-----+------------+--------+ 


Biz kesinlikle yukarıdaki kodu veya masa düzeni kullanarak üzerinde ayarlanmamış, herhangi bir çalışma çözümleri hoş olurdu.

How would you store possibly recurring times?

What's the best way to model recurring events in a calendar application?

Should I store dates or recurrence rules in my database when building a calendar app?

veya

http://tools.ietf.org/html/rfc5545

Onları kontrol ettikten ve çok kullanışlı ama yapmıyor idi: doğru beni işaret etmeyiniz niyetimizle aynı.Bir şey eksik sürece TIA

+0

'islast' nedir? Veya "tarihler" tablosunda "oluşum"? – Naltharial

+0

'islast' ayarlandığında, ayın sonuncu günü bir ay içinde işaretlenir (Örneğin, ayın son Pazartesi günü), bir ayda bir güne ait olayların sayısıdır (Örneğin, 'ayın ilk Pazartesi günü', 'ikinci Pazartesi günü ay ') – blankabout

cevap

2

cevabı şaşırtıcı basittir. Bu sütunlar farklı tablolarda olsa bile, UNION'ların bir ortak ad kullanarak ortak sütunlara ayrılabileceğini fark etmemiştim. Yani tam sorgu olacaktır:

 
SELECT DISTINCT(e.eventid),n.nameid,n.firstname,n.lastname,d.dt AS dait,r.recurring 
FROM dates d 
LEFT JOIN recurringtypes r 
/* if event recurring every week E.g. 'Every Monday' */ 
ON (r.rectypeid BETWEEN 2 AND 8 AND r.day = d.dow) 
/* if event recurring every month E.g. 'First Monday, every month' */ 
OR ((r.rectypeid BETWEEN 9 AND 36) AND r.day = d.dow AND r.occurrence = d.occurrence) 
/* if event recurring every last week of month E.g. 'Last Monday, every month' */ 
OR (r.rectypeid >= 37 AND r.day = d.dow and r.islast = d.islast) 
LEFT JOIN events e on e.rectypeid = r.rectypeid 
LEFT JOIN eventtypes t ON e.eventtypeid = t.eventtypeid 
LEFT JOIN names n ON e.namesid = n.namesid 
WHERE (d.dt BETWEEN '2012/02/01' AND '2012/05/01') 
UNION 
SELECT e.eventid,n.nameid,n.lastname,n.firstname,e.firstdate AS dait,'No' as Recurring 
FROM events e 
LEFT JOIN names n ON n.names = e.namesid 
AND e.rectypeid <= 1 
WHERE e.firstdate BETWEEN '2012/02/01' AND '2012/05/01' 
ORDER BY dait; 

tarih sonunda bitecek çünkü tarihleri ​​arayanlar için bir tablosu kullanılarak risk doğrudur ki, dikkat çekti, ancak bir tarih, örneğin olup olmadığını hesaplamak oldu, Bir ayın ilk Pazartesi günü (veya ikinci, dördüncü veya belki dördüncü ve son), şu an içine girmek istediğimden daha karmaşık bir SQL kodu gibi görünüyor.

2
SELECT DISTINCT(e.eventid),n.nameid,n.firstname,n.lastname,d.dt,r.recurring 
FROM dates d 
LEFT JOIN recurringtypes r 
/* if event recurring every week E.g. 'Every Monday' */ 
ON (r.rectypeid BETWEEN 2 AND 8 AND r.day = d.dow) 
/* if event recurring every month E.g. 'First Monday, every month' */ 
OR ((r.rectypeid BETWEEN 9 AND 36) AND r.day = d.dow AND r.occurrence = d.occurrence) 
/* if event recurring every last week of month E.g. 'Last Monday, every month' */ 
OR (r.rectypeid >= 37 AND r.day = d.dow and r.islast = d.islast) 
LEFT JOIN events e on e.rectypeid = r.rectypeid OR (e.rectypeid <= 1 AND e.eventid IS NOT NULL) 
LEFT JOIN eventtypes t ON e.eventtypeid = t.eventtypeid 
LEFT JOIN names n ON e.namesid = n.namesid 
WHERE (d.dt BETWEEN '2012/02/01' AND '2012/05/01') 
ORDER BY d.dt; 
+0

Brilliant, neredeyse! Bu gerçekten harika ve neredeyse var, ancak event.rectypeid = 1 (nüks yok) olduğunda bile yinelenen satırlar, belki de etkinlik ve yinelenen tabloların eşitlenmemesi nedeniyle mi? 'VEYA' ndan sonra kayıp bir 'VE' olabileceğinden şüpheleniyorum ama ne olması gerektiğini düşünemiyorum. – blankabout

+0

@blankabout: Durum daha az veya eşittir, ancak belki de bu sorguyu çözebilir: OR (e.rectypeid <= 1 VE e.eventid NULL DEĞİLDİR). Aksi takdirde e.tifypeid <1'i deneyebilirim? Ya da WHERE yan tümcesine e.eventid IS NOT NULL ekleyebilir misiniz? Bu daha ucuz. – Bytemain

+0

Ne yazık ki bu seçeneklerden hiçbiri yardım etmedi. Farklı bir yaklaşımın, belki de iki sorgunun bir çeşit sendikasına yardım edip edemeyeceğini merak ediyorum; ancak sendikaların benim (sınırlı) deneyimim, bunların, özellikle yararlı olmayan bir şekilde bir araya getirilen iki tamamen ayrı sorgu olduğunu gösteriyor. – blankabout