जैसा कि पहले ही दिए गए कई अद्भुत उत्तरों में कहा गया है (या कम से कम इसकी पुष्टि की गई है), इस समस्या को आसानी से हल कर लिया जाता है जब आपके पास काम करने के लिए संख्याओं का एक सेट होता है।
नोट: निम्नलिखित टी-एसक्यूएल है, लेकिन यह केवल सामान्य अवधारणाओं का मेरा विशेष रूप से कार्यान्वयन है जो पहले से ही यहां और इंटरनेट पर बड़े पैमाने पर उल्लिखित है। कोड को अपनी पसंद की बोली में बदलना अपेक्षाकृत सरल होना चाहिए।
कैसे? इस प्रश्न पर विचार करें:
SELECT DATEADD(d, N, '0001-01-22')
FROM Numbers -- A table containing the numbers 0 through N
WHERE N <= 5;
उपरोक्त तिथि सीमा 1/22/0001 - 1/27/0001 उत्पन्न करती है और यह अत्यंत तुच्छ है। : वहाँ ऊपर क्वेरी में जानकारी के 2 प्रमुख टुकड़े हैं आरंभ तिथि की 0001-01-22
और ऑफसेट की 5
। यदि हम इन दोनों सूचनाओं को जोड़ते हैं तो स्पष्ट रूप से हमारी अंतिम तिथि है। इस प्रकार, दो तिथियों को देखते हुए, एक सीमा को उत्पन्न किया जा सकता है जैसे:
दो दी गई तारीखों (ऑफसेट), आसान के बीच अंतर खोजें:
-- Returns 125
SELECT ABS(DATEDIFF(d, '2014-08-22', '2014-12-25'))
ABS()
यहाँ का उपयोग यह सुनिश्चित करता है कि तिथि क्रम अप्रासंगिक है।
संख्याओं का एक सीमित सेट उत्पन्न करें, यह भी आसान है:
-- Returns the numbers 0-2
SELECT N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1
FROM(SELECT 'A' AS S UNION ALL SELECT 'A' UNION ALL SELECT 'A')
ध्यान दें कि हम वास्तव में परवाह नहीं करते हैं कि हम FROM
यहां क्या चुन रहे हैं। हमें काम करने के लिए बस एक सेट की जरूरत है ताकि हम उसमें पंक्तियों की संख्या गिनें। मैं व्यक्तिगत रूप से एक टीवीएफ का उपयोग करता हूं, कुछ एक सीटीई का उपयोग करते हैं, अन्य इसके बजाय एक अंक तालिका का उपयोग करते हैं, आपको विचार मिलता है। मैं सबसे अधिक प्रदर्शन करने वाले समाधान का उपयोग करने की वकालत करता हूं जिसे आप भी समझते हैं।
इन दोनों तरीकों को मिलाने से हमारी समस्या दूर हो जाएगी:
DECLARE @date1 DATE = '9001-11-21';
DECLARE @date2 DATE = '9001-11-23';
SELECT D = DATEADD(d, N, @date1)
FROM (
SELECT N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1
FROM (SELECT 'A' AS S UNION ALL SELECT 'A' UNION ALL SELECT 'A') S
) Numbers
WHERE N <= ABS(DATEDIFF(d, @date1, @date2));
उपरोक्त उदाहरण भयानक कोड है, लेकिन यह दर्शाता है कि सब कुछ एक साथ कैसे आता है।
ज्यादा मस्ती
मुझे इस तरह का काम करने की ज़रूरत है इसलिए मैंने तर्क को दो टीवीएफ में बदल दिया। पहला संख्याओं की एक सीमा उत्पन्न करता है और दूसरा इस कार्यक्षमता का उपयोग तिथियों की एक श्रृंखला उत्पन्न करने के लिए करता है। गणित यह सुनिश्चित करने के लिए है कि इनपुट ऑर्डर मायने नहीं रखता और क्योंकि मैं उपलब्ध संख्याओं की पूरी श्रृंखला का उपयोग करना चाहता था GenerateRangeSmallInt
।
निम्न कार्य 65536 दिनांक की अधिकतम सीमा को वापस करने के लिए ~ 16ms CPU समय लेता है।
CREATE FUNCTION dbo.GenerateRangeDate (
@date1 DATE,
@date2 DATE
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (
SELECT D = DATEADD(d, N + 32768, CASE WHEN @date1 <= @date2 THEN @date1 ELSE @date2 END)
FROM dbo.GenerateRangeSmallInt(-32768, ABS(DATEDIFF(d, @date1, @date2)) - 32768)
);
GO
CREATE FUNCTION dbo.GenerateRangeSmallInt (
@num1 SMALLINT = -32768
, @num2 SMALLINT = 32767
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (
WITH Numbers(N) AS (
SELECT N FROM(VALUES
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 16
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 32
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 48
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 64
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 80
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 96
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 112
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 128
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 144
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 160
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 176
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 192
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 208
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 224
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 240
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 256
) V (N)
)
SELECT TOP(ABS(CAST(@num1 AS INT) - CAST(@num2 AS INT)) + 1)
N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) + CASE WHEN @num1 <= @num2 THEN @num1 ELSE @num2 END - 1
FROM Numbers A
, Numbers B
);