Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Tampilkan tanggal acara berikutnya

Langkah pertama Anda adalah mendapatkan tanggal mulai acara Anda dengan setiap acara, dan interval pengulangan, untuk melakukan ini, Anda dapat menggunakan:

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));

Ini memberikan:

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

Untuk mengulanginya, Anda memerlukan tabel angka untuk bergabung, jika Anda tidak memilikinya, ada beberapa cara untuk membuatnya dengan cepat, untuk alasan kesederhanaan saya akan menggunakan:

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

Untuk bacaan lebih lanjut, Aaron Bertrand telah melakukan beberapa perbandingan mendalam cara menghasilkan daftar angka berurutan:

  • Menghasilkan satu set atau urutan tanpa loop – part1
  • Menghasilkan satu set atau urutan tanpa loop – part2
  • Menghasilkan satu set atau urutan tanpa loop – part3

Jika kita membatasi tabel angka kita menjadi hanya 0 - 5, dan hanya melihat kejadian pertama, penggabungan silang keduanya akan menghasilkan:

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

Kemudian Anda bisa mendapatkan kemunculan Anda dengan menambahkan RepeatInterval * Number ke waktu mulai acara:

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;

Ini memberikan hasil yang Anda harapkan:

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

Contoh pada SQL Fiddle

Saya pikir skema yang Anda miliki dipertanyakan, gabung di:

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

tipis di terbaik. Saya pikir Anda akan jauh lebih baik menyimpan tanggal mulai dan interval pengulangan yang terkait dengannya bersama-sama:

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)
);

Ini akan menyederhanakan data Anda menjadi:

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

Ini juga memungkinkan Anda untuk menambahkan tanggal akhir untuk pengulangan Anda, yaitu jika Anda hanya ingin mengulanginya selama satu minggu. Ini maka kueri Anda disederhanakan menjadi:

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;

Contoh pada SQL Fiddle

Saya tidak akan memberikan skema lengkap saya tentang bagaimana saya telah mencapai ini di masa lalu, tetapi saya akan memberikan contoh yang sangat sederhana, dari mana Anda diharapkan dapat membangun sendiri. Saya hanya akan menambahkan contoh untuk acara yang diadakan setiap minggu pada Senin-Jumat:

Dalam ER RepeatEvent di atas menyimpan informasi dasar untuk acara berulang, lalu tergantung pada jenis berulang (Harian, mingguan, bulanan) satu atau lebih tabel lainnya diisi. Dalam contoh acara mingguan, itu akan menyimpan semua hari dalam seminggu yang berulang dalam tabel RepeatDay . Jika ini perlu dibatasi hanya pada bulan-bulan tertentu, Anda dapat menyimpan bulan-bulan ini di RepeatMonth , dan seterusnya.

Kemudian menggunakan tabel kalender, Anda bisa mendapatkan semua kemungkinan tanggal setelah kencan pertama, dan membatasi ini hanya pada tanggal yang cocok dengan hari dalam seminggu/bulan dalam setahun, dll:

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);

Contoh pada SQL Fiddle

Ini hanya representasi yang sangat mendasar tentang bagaimana saya menerapkannya, misalnya saya benar-benar menggunakan sepenuhnya tampilan kueri apa pun untuk data berulang sehingga setiap peristiwa tanpa entri di RepeatDayOfWeek akan diasumsikan berulang setiap hari, daripada tidak sama sekali. Bersama dengan semua detail lain dalam jawaban ini dan jawaban lainnya, semoga Anda memiliki lebih dari cukup untuk memulai.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Server BEBERAPA Operator Dijelaskan

  2. Pernyataan BERGABUNG Bersyarat SQL Server

  3. Perhatian pengguna yang menjalankan SQL Server 2008 dan SQL Server 2008 R2

  4. Membuat pemicu audit di SQL Server

  5. Gabungkan PowerShell dan SQL Diagnostic Manager untuk mengotomatiskan pemantauan SQL Server