Soy consciente de que las preguntas sobre eventos recurrentes son comunes, pero no he podido encontrar ninguna respuesta a esta pregunta específica sobre eventos recurrentes que no sean los relacionados con las aplicaciones de calendario. La principal diferencia es que los eventos en nuestra aplicación. solo se verá en los informes o por sí mismos en lugar de en un formato de calendario, aunque en muchos aspectos son muy similares, quizás solo con menos equipaje asociado con los calendarios.Eventos recurrentes, consulta SQL
De forma similar a una aplicación de calendario. los eventos pueden ocurrir de manera puntual o pueden ser recurrentes, por ej. todos los jueves o primeros lunes de cada mes, hasta algún momento preestablecido en el futuro.
Los eventos se almacenan en una tabla de eventos que contiene las fechas de inicio y final y la 'id del tipo de recurrencia'. Si el 'tipo de recurrencia' es 'Ninguno', las fechas de inicio y finalización serán las mismas. La tabla de eventos contiene una identificación en una tabla separada que contiene el nombre del tipo de evento, por ej. 'Reunión' o 'Informe semanal'
Hay otra tabla que contiene la lista de 'tipos de recurrencia' P. ej. 'Sin repetición', 'Todos los lunes', 'Primer lunes de mes' y 'Último sábado de mes'.
Para facilitar las búsquedas, otra tabla contiene una lista de fechas de 1960 a 2060 junto con información relevante sobre cada fecha, por ejemplo si es un lunes y qué ocurrencia de lunes es en el mes.
Esto permite una búsqueda, tal como:
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;
¿Qué es exactamente lo que se requiere para encontrar eventos recurrentes, dando una salida como:
+-----------+---------------+-------------------+-----------+------------+-------------------------------+
| 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 |
para conseguir ninguno acontecimientos que se repiten una consulta simple se puede utilizar:
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;
Esto da salida muy similar a la primera consulta pero, crucialmente, las fechas son de la tabla de eventos en lugar de la tabla de fechas.
Mi pregunta es: ¿Cómo puedo combinar estas consultas para llegar a una lista que contiene todos los eventos, tanto recurrentes como no recurrentes en el orden de las fechas?
Estas son las tablas y selecciones abreviadas de ellas, algunas columnas y todos los índices se han retirado por razones de brevedad :). La tabla de 'nombres' no se ha incluido por el mismo motivo.
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 |
+------------+----------+------+-------+-----+-----+------------+--------+
No nos fijamos en absoluto sobre el uso del código por encima o por disposición de la tabla, las soluciones de trabajo serían bien recibidos. Por favor, no me señale hacia:
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?
o
http://tools.ietf.org/html/rfc5545
los he comprobado y fueron muy útiles, pero no hacer el lo mismo que tenemos la intención.
TIA
¿Qué hace 'islast'? ¿O 'ocurrencia' en la tabla' fechas'? – Naltharial
Si establece banderas 'islast' la última ocurrencia de un día en un mes (por ejemplo, 'el último lunes del mes), la ocurrencia es el recuento de las ocurrencias de un día en un mes (por ejemplo,' primer lunes del mes ',' segundo lunes en mes ') – blankabout