Sqlserver
 sql >> डेटाबेस >  >> RDS >> Sqlserver

जबकि SQL Server 2008 में लूप एक दिनांक-सीमा और फिर INSERT के माध्यम से पुनरावृति करता है

एसक्यूएल एक सेट आधारित भाषा है और लूप अंतिम उपाय होना चाहिए। तो सेट आधारित दृष्टिकोण सबसे पहले आपको आवश्यक सभी तिथियों को उत्पन्न करना होगा और एक बार में लूपिंग और डालने के बजाय उन्हें एक बार में डालना होगा। हारून बर्ट्रेंड ने बिना लूप के सेट या सीक्वेंस जेनरेट करने पर एक बेहतरीन सीरीज़ लिखी है:

भाग 3 विशेष रूप से प्रासंगिक है क्योंकि यह तिथियों से संबंधित है।

मान लें कि आपके पास कैलेंडर तालिका नहीं है, तो आप अपनी प्रारंभ और समाप्ति तिथियों के बीच तिथियों की सूची बनाने के लिए स्टैक्ड सीटीई विधि का उपयोग कर सकते हैं।

DECLARE @StartDate DATE = '2015-01-01',
        @EndDate DATE = GETDATE();

WITH N1 (N) AS (SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2)
SELECT TOP (DATEDIFF(DAY, @StartDate, @EndDate) + 1)
        Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY N) - 1, @StartDate)
FROM N3;

मैंने कुछ विवरण छोड़ दिया है कि यह कैसे काम करता है क्योंकि यह लिंक किए गए आलेख में शामिल है, संक्षेप में यह 10 पंक्तियों की हार्ड कोडित तालिका से शुरू होता है, फिर इस तालिका में 100 पंक्तियां (10 x 10) प्राप्त करने के लिए स्वयं से जुड़ता है और फिर इस तालिका में शामिल हो जाता है 1000 पंक्तियों में से 10,000 पंक्तियाँ प्राप्त करने के लिए (मैं इस बिंदु पर रुक गया लेकिन यदि आपको और पंक्तियों की आवश्यकता है तो आप और जोड़ सकते हैं)।

प्रत्येक चरण में आउटपुट एक एकल कॉलम होता है जिसे N . कहा जाता है 1 के मान के साथ (चीजों को सरल रखने के लिए)। एक ही समय में 10,000 पंक्तियों को कैसे उत्पन्न किया जाए, यह परिभाषित करते हुए, मैं वास्तव में SQL सर्वर को केवल TOP का उपयोग करके आवश्यक संख्या उत्पन्न करने के लिए कहता हूं। और आपकी आरंभ और समाप्ति तिथि के बीच का अंतर - TOP(DATEDIFF(DAY, @StartDate, @EndDate) + 1) . इससे अनावश्यक काम से बचा जा सकता है। दोनों तिथियों को शामिल करने के लिए मुझे अंतर में 1 जोड़ना पड़ा।

रैंकिंग फ़ंक्शन का उपयोग करना ROW_NUMBER() मैं जेनरेट की गई प्रत्येक पंक्ति में एक वृद्धिशील संख्या जोड़ता हूं, फिर मैं तिथियों की सूची प्राप्त करने के लिए इस वृद्धिशील संख्या को आपकी प्रारंभ तिथि में जोड़ता हूं। चूंकि ROW_NUMBER() 1 से शुरू होता है, मुझे इसमें से 1 घटाना होगा ताकि यह सुनिश्चित हो सके कि प्रारंभ तिथि शामिल है।

तब यह केवल उन तारीखों को बाहर करने का मामला होगा जो पहले से मौजूद हैं NOT EXISTS . का उपयोग करके . मैंने उपरोक्त क्वेरी के परिणामों को उनके अपने सीटीई में संलग्न किया है जिसे dates . कहा जाता है :

DECLARE @StartDate DATE = '2015-01-01',
        @EndDate DATE = GETDATE();

WITH N1 (N) AS (SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Dates AS
(   SELECT TOP (DATEDIFF(DAY, @StartDate, @EndDate) + 1)
            Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY N) - 1, @StartDate)
    FROM N3
)
INSERT INTO MyTable ([TimeStamp])
SELECT  Date
FROM    Dates AS d
WHERE NOT EXISTS (SELECT 1 FROM MyTable AS t WHERE d.Date = t.[TimeStamp])

SQL Fiddle पर उदाहरण

यदि आप एक कैलेंडर तालिका बनाना चाहते हैं (जैसा कि लिंक किए गए लेखों में वर्णित है) तो इन अतिरिक्त पंक्तियों को सम्मिलित करना आवश्यक नहीं हो सकता है, आप बस अपना परिणाम सेट फ्लाई पर उत्पन्न कर सकते हैं, जैसे कुछ:

SELECT  [Timestamp] = c.Date,
        t.[FruitType],
        t.[NumOffered],
        t.[NumTaken],
        t.[NumAbandoned],
        t.[NumSpoiled]
FROM    dbo.Calendar AS c
        LEFT JOIN dbo.MyTable AS t
            ON t.[Timestamp] = c.[Date]
WHERE   c.Date >= @StartDate
AND     c.Date < @EndDate;

अतिरिक्त

आपके वास्तविक प्रश्न का उत्तर देने के लिए आपका लूप इस प्रकार लिखा जाएगा:

DECLARE @StartDate AS DATETIME
DECLARE @EndDate AS DATETIME
DECLARE @CurrentDate AS DATETIME

SET @StartDate = '2015-01-01'
SET @EndDate = GETDATE()
SET @CurrentDate = @StartDate

WHILE (@CurrentDate < @EndDate)
BEGIN
    IF NOT EXISTS (SELECT 1 FROM myTable WHERE myTable.Timestamp = @CurrentDate)
    BEGIN
        INSERT INTO MyTable ([Timestamp])
        VALUES (@CurrentDate);
    END

    SET @CurrentDate = DATEADD(DAY, 1, @CurrentDate); /*increment current date*/
END

SQL Fiddle पर उदाहरण

मैं इस दृष्टिकोण की वकालत नहीं करता, सिर्फ इसलिए कि कुछ केवल एक बार किया जा रहा है इसका मतलब यह नहीं है कि मुझे इसे करने का सही तरीका नहीं दिखाना चाहिए।

आगे की व्याख्या

चूंकि स्टैक्ड सीटीई पद्धति सेट आधारित दृष्टिकोण को अधिक जटिल बना सकती है, इसलिए मैं इसे अनियंत्रित सिस्टम टेबल master..spt_values का उपयोग करके सरल बनाऊंगा। . यदि आप दौड़ते हैं:

SELECT Number
FROM master..spt_values
WHERE Type = 'P';

आप देखेंगे कि आपको 0 -2047 से सभी नंबर मिल गए हैं।

अब अगर आप दौड़ते हैं:

DECLARE @StartDate DATE = '2015-01-01',
        @EndDate DATE = GETDATE();


SELECT Date = DATEADD(DAY, number, @StartDate)
FROM master..spt_values
WHERE type = 'P';

आपको अपनी आरंभ तिथि से लेकर भविष्य में 2047 दिनों तक की सभी तिथियां मिलती हैं। यदि आप एक और जहां क्लॉज जोड़ते हैं तो आप इसे अपनी समाप्ति तिथि से पहले की तारीखों तक सीमित कर सकते हैं:

DECLARE @StartDate DATE = '2015-01-01',
        @EndDate DATE = GETDATE();


SELECT Date = DATEADD(DAY, number, @StartDate)
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY, number, @StartDate) <= @EndDate;

अब आपके पास एक सेट आधारित क्वेरी में आवश्यक सभी तिथियां हैं, आप NOT EXISTS का उपयोग करके अपनी तालिका में पहले से मौजूद पंक्तियों को समाप्त कर सकते हैं

DECLARE @StartDate DATE = '2015-01-01',
        @EndDate DATE = GETDATE();


SELECT Date = DATEADD(DAY, number, @StartDate)
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY, number, @StartDate) <= @EndDate
AND NOT EXISTS (SELECT 1 FROM MyTable AS t WHERE t.[Timestamp] = DATEADD(DAY, number, @StartDate));

अंत में आप INSERT . का उपयोग करके इन तिथियों को अपनी तालिका में सम्मिलित कर सकते हैं

DECLARE @StartDate DATE = '2015-01-01',
        @EndDate DATE = GETDATE();

INSERT YourTable ([Timestamp])
SELECT Date = DATEADD(DAY, number, @StartDate)
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY, number, @StartDate) <= @EndDate
AND NOT EXISTS (SELECT 1 FROM MyTable AS t WHERE t.[Timestamp] = DATEADD(DAY, number, @StartDate));

उम्मीद है कि यह किसी तरह यह दिखाने के लिए जाता है कि सेट आधारित दृष्टिकोण न केवल अधिक कुशल है बल्कि सरल भी है।



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. पूर्णांक डेटाटाइप के साथ एसक्यूएल सर्वर कॉलम में खाली रखें

  2. संपूर्ण तालिका पर परिवर्तन डेटा कैप्चर (सीडीसी) को कैसे सक्षम करें या SQL सर्वर में कॉलम की सूची के साथ तालिका में सीडीसी को सक्षम करें

  3. मैं SQL सर्वर तालिका से हटाए गए रिकॉर्ड कैसे देख सकता हूं?

  4. दूरस्थ SQL सर्वर पर BCP का उपयोग करके कैसे लिखें?

  5. तालिका के सेट पर सीडीसी को अक्षम कैसे करें या SQL सर्वर में डेटाबेस में सभी तालिकाओं पर अक्षम करें - SQL सर्वर ट्यूटोरियल