आपका पहला कदम यह है कि आप प्रत्येक ईवेंट के साथ अपना ईवेंट प्रारंभ दिनांक प्राप्त करें, और दोहराव अंतराल, ऐसा करने के लिए आप इसका उपयोग कर सकते हैं:
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));
यह देता है:
EventID | Name | StartDateTime | RepeatInterval
--------+--------------+---------------------+-----------------
1 | Billa Vist | 2014-01-03 10:00:00 | 604800
1 | Billa Vist | 2014-01-04 18:00:00 | 604800
इसे दोहराने के लिए आपको क्रॉस जॉइन करने के लिए एक नंबर टेबल की आवश्यकता होगी, यदि आपके पास एक नहीं है तो फ्लाई पर एक उत्पन्न करने के कई तरीके हैं, सरल कारणों से मैं इसका उपयोग करूंगा:
WITH Numbers AS
( SELECT Number = ROW_NUMBER() OVER(ORDER BY a.object_id) - 1
FROM sys.all_objects a
)
SELECT Number
FROM Numbers;
आगे पढ़ने के लिए, आरोन बर्ट्रेंड ने संख्याओं की अनुक्रमिक सूचियाँ बनाने के तरीकों की गहराई से तुलना की है:
- लूप के बिना एक सेट या अनुक्रम उत्पन्न करें - part1
- लूप के बिना एक सेट या अनुक्रम उत्पन्न करें - part2
- बिना लूप के एक सेट या अनुक्रम जेनरेट करें - part3
यदि हम अपनी संख्या तालिका को केवल 0 - 5 तक सीमित रखते हैं, और केवल पहली घटना को देखते हैं, तो दोनों को क्रॉस जॉइन करने से निम्न मिलेगा:
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
फिर आप RepeatInterval * Number
. जोड़कर अपना मौका पा सकते हैं घटना शुरू होने के समय के लिए:
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;
यह आपका अपेक्षित आउटपुट देता है:
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
SQL Fiddle पर उदाहरण
मुझे लगता है कि आपके पास जो स्कीमा है वह संदिग्ध है, हालांकि इसमें शामिल हों:
Meta_Key = 'repeat_interval_' + CAST(rs.ID AS VARCHAR(10))
सबसे अच्छा तुच्छ है। मुझे लगता है कि बेहतर होगा कि आप आरंभ तिथि और उससे जुड़े अंतराल को एक साथ संगृहीत करें:
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)
);
यह आपके डेटा को सरल बना देगा:
EventID | StartDateTime | RepeatInterval | RepeatEndDate
--------+---------------------+----------------+---------------
1 | 2014-01-03 10:00:00 | 604800 | NULL
1 | 2014-01-04 18:00:00 | 604800 | NULL
यह आपको अपने दोहराने के लिए एक समाप्ति तिथि जोड़ने की अनुमति देता है, अर्थात यदि आप इसे केवल एक सप्ताह के लिए दोहराना चाहते हैं। इसके बाद आपकी क्वेरी सरल हो जाती है:
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;
SQL Fiddle पर उदाहरण
मैं आपको अपना पूरा स्कीमा नहीं दूंगा कि मैंने इसे अतीत में कैसे हासिल किया है, लेकिन मैं एक बहुत ही कटा हुआ उदाहरण दूंगा, जिससे आप उम्मीद कर सकते हैं कि आप अपना खुद का निर्माण कर सकते हैं। मैं केवल सोम-शुक्र को साप्ताहिक रूप से होने वाली घटना के लिए एक उदाहरण जोड़ूंगा:
उपरोक्त ईआर रिपीटएवेंट में आवर्ती घटना के लिए बुनियादी जानकारी संग्रहीत होती है, फिर दोहराने के प्रकार (दैनिक, साप्ताहिक, मासिक) के आधार पर एक या अधिक अन्य तालिकाओं को पॉप्युलेट किया जाता है। साप्ताहिक ईवेंट के उदाहरण में, यह सप्ताह के उन सभी दिनों को संग्रहीत करेगा, जिन्हें वह RepeatDay
तालिका में दोहराता है . यदि इसे केवल कुछ महीनों तक सीमित रखने की आवश्यकता है, तो आप इन महीनों को RepeatMonth
में संग्रहीत कर सकते हैं , और इसी तरह।
फिर कैलेंडर तालिका का उपयोग करके आप पहली तारीख के बाद सभी संभावित तिथियां प्राप्त कर सकते हैं, और इन्हें केवल उन तिथियों तक सीमित कर सकते हैं जो वर्ष के सप्ताह/माह के दिन से मेल खाते हैं:
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);
SQL Fiddle पर उदाहरण
यह केवल एक बहुत ही बुनियादी प्रतिनिधित्व है कि मैंने इसे कैसे कार्यान्वित किया, उदाहरण के लिए मैंने वास्तव में दोहराए जाने वाले डेटा के लिए किसी भी प्रश्न को पूरी तरह से देखा ताकि कोई भी घटना जिसमें कोई प्रविष्टि न हो RepeatDayOfWeek
हर दिन दोहराने के लिए माना जाएगा, न कि कभी नहीं। इस और अन्य उत्तरों में अन्य सभी विवरणों के साथ, आपको उम्मीद है कि आपको आरंभ करने के लिए पर्याप्त से अधिक होना चाहिए।