sql >> Database >  >> RDS >> Sqlserver

Datum volgende gebeurtenis weergeven

Je eerste stap is om de startdatums van je evenement bij elk evenement te krijgen, en het herhalingsinterval, om dit te doen, kun je het volgende gebruiken:

SELECT  EventID = e.ID, 
        e.Name, 
        StartDateTime = DATEADD(SECOND, rs.Meta_Value, '19700101'),
        RepeatInterval = ri.Meta_Value
FROM    dbo.Events e
        INNER JOIN dbo.Events_Meta rs
            ON rs.Event_ID = e.ID
            AND rs.Meta_Key = 'repeat_start'
        INNER JOIN dbo.Events_Meta ri
            ON ri.Event_ID = e.ID
            AND ri.Meta_Key = 'repeat_interval_' + CAST(e.ID AS VARCHAR(10));

Dit geeft:

EventID | Name         | StartDateTime       | RepeatInterval
--------+--------------+---------------------+-----------------
   1    | Billa Vist   | 2014-01-03 10:00:00 |     604800
   1    | Billa Vist   | 2014-01-04 18:00:00 |     604800

Om dit te laten herhalen heb je een getallentabel nodig om mee te cross-joinen. Als je er geen hebt, zijn er een aantal manieren om er meteen een te genereren, om redenen van eenvoud zal ik gebruiken:

WITH Numbers AS
(   SELECT  Number = ROW_NUMBER() OVER(ORDER BY a.object_id) - 1
    FROM    sys.all_objects a
)
SELECT  Number
FROM    Numbers;

Voor meer informatie heeft Aaron Bertrand een aantal diepgaande vergelijkingen gemaakt om opeenvolgende lijsten met getallen te genereren:

  • Genereer een set of reeks zonder lussen – deel1
  • Genereer een set of reeks zonder loops – part2
  • Genereer een set of reeks zonder loops – part3

Als we onze tafel met getallen beperken tot alleen 0 - 5, en alleen naar de eerste gebeurtenis kijken, levert het kruisen van de twee het volgende op:

EventID | Name         | StartDateTime       | RepeatInterval | Number
--------+--------------+---------------------+----------------+---------
   1    | Billa Vist   | 2014-01-03 10:00:00 |     604800     |    0
   1    | Billa Vist   | 2014-01-03 10:00:00 |     604800     |    1
   1    | Billa Vist   | 2014-01-03 10:00:00 |     604800     |    2
   1    | Billa Vist   | 2014-01-03 10:00:00 |     604800     |    3
   1    | Billa Vist   | 2014-01-03 10:00:00 |     604800     |    4
   1    | Billa Vist   | 2014-01-03 10:00:00 |     604800     |    5

Dan kunt u uw voorkomen krijgen door RepeatInterval * Number . toe te voegen naar de starttijd van het evenement:

DECLARE @EndDate DATETIME = '20140130';

WITH EventData AS
(   SELECT  EventID = e.ID, 
            e.Name, 
            StartDateTime = DATEADD(SECOND, rs.Meta_Value, '19700101'),
            RepeatInterval = ri.Meta_Value
    FROM    dbo.Events e
            INNER JOIN dbo.Events_Meta rs
                ON rs.Event_ID = e.ID
                AND rs.Meta_Key = 'repeat_start'
            INNER JOIN dbo.Events_Meta ri
                ON ri.Event_ID = e.ID
                AND ri.Meta_Key = 'repeat_interval_' + CAST(rs.ID AS VARCHAR(10))
), Numbers AS
(   SELECT  Number = ROW_NUMBER() OVER(ORDER BY a.object_id) - 1
    FROM    sys.all_objects a
)
SELECT  e.EventID,
        e.Name,
        EventDate = DATEADD(SECOND, n.Number * e.RepeatInterval, e.StartDateTime)
FROM    EventData e
        CROSS JOIN Numbers n
WHERE   DATEADD(SECOND, n.Number * e.RepeatInterval, e.StartDateTime) < @EndDate
ORDER BY e.EventID, EventDate;

Dit geeft uw verwachte output:

EVENTID | NAME          | EVENTDATE
--------+---------------+--------------------------------
   1    | Billa Vist    | January, 03 2014 10:00:00+0000
   1    | Billa Vist    | January, 04 2014 18:00:00+0000
   1    | Billa Vist    | January, 10 2014 10:00:00+0000
   1    | Billa Vist    | January, 11 2014 18:00:00+0000
   1    | Billa Vist    | January, 17 2014 10:00:00+0000
   1    | Billa Vist    | January, 18 2014 18:00:00+0000
   1    | Billa Vist    | January, 24 2014 10:00:00+0000
   1    | Billa Vist    | January, 25 2014 18:00:00+0000

Voorbeeld op SQL Fiddle

Ik denk dat het schema dat je hebt twijfelachtig is, de join on:

Meta_Key = 'repeat_interval_' + CAST(rs.ID AS VARCHAR(10))

is op zijn best fragiel. Ik denk dat het veel beter is om de startdatum en het bijbehorende herhalingsinterval samen op te slaan:

CREATE TABLE dbo.Events_Meta
(       ID INT IDENTITY(1, 1) NOT NULL,
        Event_ID INT NOT NULL,
        StartDateTime DATETIME2 NOT NULL,
        IntervalRepeat INT NULL, -- NULLABLE FOR SINGLE EVENTS
        RepeatEndDate DATETIME2 NULL, -- NULLABLE FOR EVENTS THAT NEVER END
    CONSTRAINT PK_Events_Meta__ID PRIMARY KEY (ID),
    CONSTRAINT FK_Events_Meta__Event_ID FOREIGN KEY (Event_ID) REFERENCES dbo.Events (ID)
);

Dit zou uw gegevens vereenvoudigen tot:

EventID | StartDateTime       | RepeatInterval | RepeatEndDate
--------+---------------------+----------------+---------------
   1    | 2014-01-03 10:00:00 |    604800      |     NULL
   1    | 2014-01-04 18:00:00 |    604800      |     NULL

U kunt ook een einddatum aan uw herhaling toevoegen, d.w.z. als u wilt dat deze slechts één week wordt herhaald. Dit vereenvoudigt uw vraag tot:

DECLARE @EndDate DATETIME = '20140130';
WITH Numbers AS
(   SELECT  Number = ROW_NUMBER() OVER(ORDER BY a.object_id) - 1
    FROM    sys.all_objects a
)
SELECT  e.ID,
        e.Name,
        EventDate = DATEADD(SECOND, n.Number * em.IntervalRepeat, em.StartDateTime) 
FROM    Events e
        INNER JOIN Events_Meta em
            ON em.Event_ID = e.ID
        CROSS JOIN Numbers n
WHERE   DATEADD(SECOND, n.Number * em.IntervalRepeat, em.StartDateTime) <= @EndDate
AND (   DATEADD(SECOND, n.Number * em.IntervalRepeat, em.StartDateTime) <= em.RepeatEndDate 
    OR  em.RepeatEndDate IS NULL
    )
ORDER BY EventDate;

Voorbeeld op SQL Fiddle

Ik zal je niet mijn volledige schema geven van hoe ik dit in het verleden heb bereikt, maar ik zal een heel kort voorbeeld geven, waaruit je hopelijk je eigen schema kunt bouwen. Ik zal alleen een voorbeeld toevoegen voor een evenement dat wekelijks plaatsvindt op ma-vr:

In het bovenstaande slaat ER RepeatEvent de basisinformatie op voor het terugkerende evenement, waarna, afhankelijk van het herhalingstype (dagelijks, wekelijks, maandelijks) een of meer van de andere tabellen worden gevuld. In een voorbeeld van een wekelijkse gebeurtenis zou het alle dagen van de week waarin het zich herhaalt opslaan in de tabel RepeatDay . Als dit beperkt moest worden tot bepaalde maanden, zou u deze maanden kunnen opslaan in RepeatMonth , enzovoort.

Vervolgens kunt u met behulp van een kalendertabel alle mogelijke datums na de eerste datum krijgen en deze beperken tot alleen die datums die overeenkomen met de dag van de week/maand van het jaar enz.:

WITH RepeatingEvents AS
(   SELECT  e.Name,
            re.StartDateTime,
            re.EndDateTime,
            re.TimesToRepeat,
            RepeatEventDate = CAST(c.DateKey AS DATETIME) + CAST(re.StartTime AS DATETIME),
            RepeatNumber = ROW_NUMBER() OVER(PARTITION BY re.RepeatEventID ORDER BY c.Datekey)
    FROM    dbo.Event e
            INNER JOIN dbo.RepeatEvent re
                ON e.EventID = re.EventID
            INNER JOIN dbo.RepeatType rt
                ON rt.RepeatTypeID = re.RepeatTypeID
            INNER JOIN dbo.Calendar c
                ON c.DateKey >= re.StartDate
            INNER JOIN dbo.RepeatDayOfWeek rdw
                ON rdw.RepeatEventID = re.RepeatEventID
                AND rdw.DayNumberOfWeek = c.DayNumberOfWeek
    WHERE   rt.Name = 'Weekly'
)
SELECT  Name, StartDateTime, RepeatEventDate, RepeatNumber
FROM    RepeatingEvents
WHERE   (TimesToRepeat IS NULL OR RepeatNumber <= TimesToRepeat)
AND     (EndDateTime IS NULL OR RepeatEventDate <= EndDateTime);

Voorbeeld op SQL Fiddle

Dit is slechts een zeer eenvoudige weergave van hoe ik het heb geïmplementeerd, ik heb bijvoorbeeld elke query voor de herhalende gegevens volledig bekeken, zodat elke gebeurtenis zonder vermeldingen in RepeatDayOfWeek zou worden verondersteld zich elke dag te herhalen, in plaats van nooit. Samen met alle andere details in deze en andere antwoorden, zou je hopelijk meer dan genoeg moeten hebben om je op weg te helpen.



  1. Kan geen verbinding maken met MySQL-serverfout 111

  2. RODBC odbcDriverConnect() Verbindingsfout

  3. Hoe hernoem je het geüploade bestand voordat je het in een map opslaat?

  4. Hoe Apache Cassandra te installeren op Ubuntu 20.10/Ubuntu 20.04