इस समस्या के साथ आपको जो समस्या होने वाली है, वह यह है कि जैसे-जैसे डेटा सेट बढ़ता है, टीएसक्यूएल के साथ इसे हल करने का समाधान अच्छी तरह से नहीं होगा। नीचे समस्या को हल करने के लिए फ्लाई पर निर्मित अस्थायी तालिकाओं की एक श्रृंखला का उपयोग किया गया है। यह एक संख्या तालिका का उपयोग करके प्रत्येक दिनांक सीमा प्रविष्टि को उसके संबंधित दिनों में विभाजित करता है। यह वह जगह है जहां यह पैमाना नहीं होगा, मुख्य रूप से आपके खुले रेंज वाले NULL मानों के कारण जो अनंत प्रतीत होते हैं, इसलिए आपको भविष्य में एक निश्चित तिथि में स्वैप करना होगा जो रूपांतरण की सीमा को संभव लंबाई तक सीमित कर देता है। आप प्रत्येक दिन के अनुकूलित प्रतिपादन के लिए उपयुक्त अनुक्रमण के साथ दिनों की तालिका या कैलेंडर तालिका बनाकर बेहतर प्रदर्शन देख सकते हैं।
एक बार श्रेणियों को विभाजित करने के बाद, विवरण एक्सएमएल पाथ का उपयोग करके विलय कर दिए जाते हैं ताकि रेंज श्रृंखला में प्रत्येक दिन इसके लिए सूचीबद्ध सभी विवरण हों। व्यक्ति आईडी और दिनांक द्वारा पंक्ति क्रमांकन प्रत्येक श्रेणी की पहली और अंतिम पंक्ति के लिए दो NOT EXISTS चेक का उपयोग करके उन उदाहरणों को खोजने की अनुमति देता है जहां मिलान करने वाले व्यक्ति और विवरण सेट के लिए पिछली पंक्ति मौजूद नहीं है, या जहां अगली पंक्ति ' t मेल खाने वाले PersonID और विवरण सेट के लिए मौजूद है।
इस परिणाम सेट को फिर ROW_NUMBER का उपयोग करके फिर से क्रमांकित किया जाता है ताकि अंतिम परिणाम बनाने के लिए उन्हें जोड़ा जा सके।
/*
SET DATEFORMAT dmy
USE tempdb;
GO
CREATE TABLE Schedule
( PersonID int,
Surname nvarchar(30),
FirstName nvarchar(30),
Description nvarchar(100),
StartDate datetime,
EndDate datetime)
GO
INSERT INTO Schedule VALUES (18, 'Smith', 'John', 'Poker Club', '01/01/2009', NULL)
INSERT INTO Schedule VALUES (18, 'Smith', 'John', 'Library', '05/01/2009', '18/01/2009')
INSERT INTO Schedule VALUES (18, 'Smith', 'John', 'Gym', '10/01/2009', '28/01/2009')
INSERT INTO Schedule VALUES (26, 'Adams', 'Jane', 'Pilates', '03/01/2009', '16/02/2009')
GO
*/
SELECT
PersonID,
Description,
theDate
INTO #SplitRanges
FROM Schedule, (SELECT DATEADD(dd, number, '01/01/2008') AS theDate
FROM master..spt_values
WHERE type = N'P') AS DayTab
WHERE theDate >= StartDate
AND theDate <= isnull(EndDate, '31/12/2012')
SELECT
ROW_NUMBER() OVER (ORDER BY PersonID, theDate) AS rowid,
PersonID,
theDate,
STUFF((
SELECT '/' + Description
FROM #SplitRanges AS s
WHERE s.PersonID = sr.PersonID
AND s.theDate = sr.theDate
FOR XML PATH('')
), 1, 1,'') AS Descriptions
INTO #MergedDescriptions
FROM #SplitRanges AS sr
GROUP BY PersonID, theDate
SELECT
ROW_NUMBER() OVER (ORDER BY PersonID, theDate) AS ID,
*
INTO #InterimResults
FROM
(
SELECT *
FROM #MergedDescriptions AS t1
WHERE NOT EXISTS
(SELECT 1
FROM #MergedDescriptions AS t2
WHERE t1.PersonID = t2.PersonID
AND t1.RowID - 1 = t2.RowID
AND t1.Descriptions = t2.Descriptions)
UNION ALL
SELECT *
FROM #MergedDescriptions AS t1
WHERE NOT EXISTS
(SELECT 1
FROM #MergedDescriptions AS t2
WHERE t1.PersonID = t2.PersonID
AND t1.RowID = t2.RowID - 1
AND t1.Descriptions = t2.Descriptions)
) AS t
SELECT DISTINCT
PersonID,
Surname,
FirstName
INTO #DistinctPerson
FROM Schedule
SELECT
t1.PersonID,
dp.Surname,
dp.FirstName,
t1.Descriptions,
t1.theDate AS StartDate,
CASE
WHEN t2.theDate = '31/12/2012' THEN NULL
ELSE t2.theDate
END AS EndDate
FROM #DistinctPerson AS dp
JOIN #InterimResults AS t1
ON t1.PersonID = dp.PersonID
JOIN #InterimResults AS t2
ON t2.PersonID = t1.PersonID
AND t1.ID + 1 = t2.ID
AND t1.Descriptions = t2.Descriptions
DROP TABLE #SplitRanges
DROP TABLE #MergedDescriptions
DROP TABLE #DistinctPerson
DROP TABLE #InterimResults
/*
DROP TABLE Schedule
*/
उपरोक्त समाधान अतिरिक्त विवरणों के बीच अंतराल को भी संभालेगा, इसलिए यदि आप एक अंतर छोड़कर व्यक्ति आईडी 18 के लिए एक और विवरण जोड़ना चाहते हैं:
INSERT INTO Schedule VALUES (18, 'Smith', 'John', 'Gym', '10/02/2009', '28/02/2009')
यह अंतर को उचित रूप से भर देगा। जैसा कि टिप्पणियों में बताया गया है, आपके पास इस तालिका में नाम की जानकारी नहीं होनी चाहिए, इसे एक व्यक्ति तालिका में सामान्यीकृत किया जाना चाहिए जिसे अंतिम परिणाम में शामिल किया जा सकता है। मैंने उस जॉइन को बनाने के लिए एक अस्थायी तालिका बनाने के लिए SELECT DISTINCT का उपयोग करके इस अन्य तालिका का अनुकरण किया।