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

DatedIFF () SQL सर्वर में गलत परिणाम देता है? इसे पढ़ें।

यदि आपको DATEDIFF() . का उपयोग करते समय कुछ बहुत ही अजीब परिणाम मिल रहे हैं SQL सर्वर में काम करता है, और आप आश्वस्त हैं कि फ़ंक्शन में एक बग है, अभी अपने बालों को न फाड़ें। यह शायद कोई बग नहीं है।

ऐसे परिदृश्य हैं जहां इस फ़ंक्शन द्वारा उत्पादित परिणाम बहुत अजीब हो सकते हैं। और यदि आप यह नहीं समझते हैं कि फ़ंक्शन वास्तव में कैसे काम करता है, तो परिणाम पूरी तरह से गलत दिखाई देंगे।

उम्मीद है कि यह लेख स्पष्ट करने में मदद कर सकता है कि कैसे DATEDIFF() फ़ंक्शन काम करने के लिए डिज़ाइन किया गया है, और कुछ उदाहरण परिदृश्य प्रदान करता है जहां आपके परिणाम आपकी अपेक्षा के अनुरूप नहीं हो सकते हैं।

उदाहरण 1 - 365 दिन हमेशा एक वर्ष नहीं होता

प्रश्न: 365 दिन कब होते हैं नहीं एक साल?

उत्तर: DATEDIFF() using का उपयोग करते समय बिल्कुल!

यहां एक उदाहरण दिया गया है जहां मैं DATEDIFF() का उपयोग करता हूं दो तिथियों के बीच दिनों की संख्या और फिर उन्हीं दो तिथियों के बीच के वर्षों की संख्या लौटाने के लिए।

DECLARE 
  @startdate datetime2 = '2016-01-01  00:00:00.0000000', 
  @enddate datetime2 = '2016-12-31 23:59:59.9999999';
SELECT 
  DATEDIFF(day, @startdate, @enddate) Days,
  DATEDIFF(year, @startdate, @enddate) Years;

परिणाम:

+--------+---------+
| Days   | Years   |
|--------+---------|
| 365    | 0       |
+--------+---------+

अगर आपको लगता है कि यह परिणाम गलत है, और वह DATEDIFF() स्पष्ट रूप से एक बग है, पढ़ें - सब कुछ वैसा नहीं है जैसा लगता है।

मानो या न मानो, यह वास्तव में अपेक्षित परिणाम है। यह परिणाम बिल्कुल DATEDIFF() . के अनुसार है काम करने के लिए डिज़ाइन किया गया है।

उदाहरण 2 - 100 नैनोसेकंड =1 वर्ष?

चलिए इसे दूसरे तरीके से लेते हैं।

DECLARE @startdate datetime2 = '2016-12-31 23:59:59.9999999', 
  @enddate datetime2 = '2017-01-01 00:00:00.0000000';

SELECT DATEDIFF(year,     @startdate,   @enddate) Year,
  DATEDIFF(quarter,       @startdate,   @enddate) Quarter,
  DATEDIFF(month,         @startdate,   @enddate) Month,
  DATEDIFF(dayofyear,     @startdate,   @enddate) DOY,
  DATEDIFF(day,           @startdate,   @enddate) Day,
  DATEDIFF(week,          @startdate,   @enddate) Week,
  DATEDIFF(hour,          @startdate,   @enddate) Hour,
  DATEDIFF(minute,        @startdate,   @enddate) Minute,
  DATEDIFF(second,        @startdate,   @enddate) Second,
  DATEDIFF(millisecond,   @startdate,   @enddate) Millisecond,
  DATEDIFF(microsecond,   @startdate,   @enddate) Microsecond,
  DATEDIFF(nanosecond,    @startdate,   @enddate) Nanosecond;

परिणाम (ऊर्ध्वाधर आउटपुट के साथ दिखाए गए):

Year        | 1
Quarter     | 1
Month       | 1
DOY         | 1
Day         | 1
Week        | 1
Hour        | 1
Minute      | 1
Second      | 1
Millisecond | 1
Microsecond | 1
Nanosecond  | 100

दो तिथियों/समयों के बीच केवल सौ नैनोसेकंड (.0000001 सेकंड) का अंतर है, फिर भी हमें नैनोसेकंड को छोड़कर, हर डेटपार्ट के लिए बिल्कुल समान परिणाम मिलता है।

ये केसे हो सकता हे? यह 1 माइक्रोसेकंड का अंतर और 1 वर्ष का अंतर दोनों एक ही समय में कैसे हो सकता है? बीच में सभी डेटपार्ट्स का उल्लेख नहीं करना है?

यह पागल लग सकता है, लेकिन यह बग भी नहीं है। ये परिणाम बिल्कुल उसी के अनुसार हैं जैसे DATEDIFF() काम करने वाला है।

और चीजों को और अधिक भ्रमित करने के लिए, हम डेटा प्रकार के आधार पर अलग-अलग परिणाम प्राप्त कर सकते हैं। लेकिन हम जल्द ही उस पर पहुंच जाएंगे। सबसे पहले देखते हैं कि DATEDIFF() फ़ंक्शन वास्तव में काम करता है।

DATEDIFF की वास्तविक परिभाषा ()

हम जो परिणाम प्राप्त करते हैं उसका कारण यह है कि DATEDIFF() फ़ंक्शन को इस प्रकार परिभाषित किया गया है:

<ब्लॉकक्वॉट>

यह फ़ंक्शन निर्दिष्ट प्रारंभ दिनांक के बीच पार की गई निर्दिष्ट दिनांक भाग सीमाओं की गणना (एक हस्ताक्षरित पूर्णांक मान के रूप में) देता है और समाप्ति तिथि

"डेटपार्ट बाउंड्री क्रॉस्ड" शब्दों पर विशेष ध्यान दें। यही कारण है कि हम पिछले उदाहरणों में परिणाम प्राप्त करते हैं। यह मान लेना आसान है कि DATEDIFF() इसकी गणना के लिए बीता हुआ समय उपयोग करता है, लेकिन ऐसा नहीं करता है। यह पार की गई डेटपार्ट सीमाओं की संख्या का उपयोग करता है।

पहले उदाहरण में, तिथियां किसी भी वर्ष-भाग की सीमाओं को पार नहीं करती थीं। पहली तारीख का वर्ष ठीक दूसरी तारीख के वर्ष के समान था। कोई सीमा नहीं लांघी।

दूसरे उदाहरण में, हमारे पास विपरीत परिदृश्य था। तिथियां कम से कम एक बार (नैनोसेकंड के लिए 100 बार) प्रत्येक डेटपार्ट सीमा को पार कर जाती हैं।

उदाहरण 3 - सप्ताह के लिए एक अलग परिणाम

अब, मान लीजिए कि एक पूरा साल बीत चुका है। और यहां हम ठीक एक वर्ष बाद दिनांक/समय मानों के साथ हैं, सिवाय इसके कि वर्ष मान एक से बढ़ गए हैं।

हमें वही परिणाम मिलना चाहिए, है ना?

DECLARE @startdate datetime2 = '2017-12-31 23:59:59.9999999', 
  @enddate datetime2 = '2018-01-01 00:00:00.0000000';

SELECT DATEDIFF(year,     @startdate,   @enddate) Year,
  DATEDIFF(quarter,       @startdate,   @enddate) Quarter,
  DATEDIFF(month,         @startdate,   @enddate) Month,
  DATEDIFF(dayofyear,     @startdate,   @enddate) DOY,
  DATEDIFF(day,           @startdate,   @enddate) Day,
  DATEDIFF(week,          @startdate,   @enddate) Week,
  DATEDIFF(hour,          @startdate,   @enddate) Hour,
  DATEDIFF(minute,        @startdate,   @enddate) Minute,
  DATEDIFF(second,        @startdate,   @enddate) Second,
  DATEDIFF(millisecond,   @startdate,   @enddate) Millisecond,
  DATEDIFF(microsecond,   @startdate,   @enddate) Microsecond,
  DATEDIFF(nanosecond,    @startdate,   @enddate) Nanosecond;

परिणाम:

Year        | 1
Quarter     | 1
Month       | 1
DOY         | 1
Day         | 1
Week        | 0
Hour        | 1
Minute      | 1
Second      | 1
Millisecond | 1
Microsecond | 1
Nanosecond  | 100

गलत।

उनमें से ज्यादातर वही हैं, लेकिन इस बार सप्ताह लौटा 0

हुह?

ऐसा इसलिए हुआ क्योंकि इनपुट तिथियों का एक ही कैलेंडर है सप्ताह मूल्य। ऐसा ही हुआ कि उदाहरण 2 के लिए चुनी गई तिथियों में कैलेंडर सप्ताह के अलग-अलग मान थे।

अधिक विशिष्ट होने के लिए, उदाहरण 2 ने '2016-12-31' से '2017-01-01' तक जाने वाली सप्ताह-भाग की सीमाओं को पार किया। ऐसा इसलिए है क्योंकि 2016 का अंतिम सप्ताह 2016-12-31 को समाप्त हुआ, और 2017 का पहला सप्ताह 2017-01-01 (रविवार) को शुरू हुआ।

लेकिन उदाहरण 3 में, 2018 का पहला सप्ताह वास्तव में 2017-12-31 (रविवार) की हमारी आरंभ तिथि से शुरू हुआ। हमारी अंतिम तिथि, अगला दिन होने के कारण, उसी सप्ताह के भीतर गिर गई। इसलिए, सप्ताह के किसी भी भाग की सीमाओं को पार नहीं किया गया।

यह स्पष्ट रूप से मानता है कि रविवार हर सप्ताह का पहला दिन है। जैसा कि यह निकला, DATEDIFF() कार्य करता है मान लें कि रविवार सप्ताह का पहला दिन है। यह आपके SET DATEFIRST . पर भी ध्यान नहीं देता है सेटिंग (यह सेटिंग आपको स्पष्ट रूप से निर्दिष्ट करने की अनुमति देती है कि कौन सा दिन सप्ताह का पहला दिन माना जाता है)। SET DATEFIRST . को नज़रअंदाज़ करने के लिए Microsoft का तर्क क्या यह सुनिश्चित करता है कि DATEDIFF() कार्य नियतात्मक है। यदि यह आपके लिए एक समस्या है तो यहां एक समाधान है।

तो संक्षेप में, आपके परिणाम दिनांक/समय के आधार पर किसी भी डेटपार्ट के लिए "गलत" दिख सकते हैं। सप्ताह-भाग का उपयोग करते समय आपके परिणाम अतिरिक्त गलत लग सकते हैं। और यदि आप SET DATEFIRST . का उपयोग करते हैं तो वे और भी गलत दिख सकते हैं 7 के अलावा (रविवार के लिए) मान और आप DATEDIFF() . की अपेक्षा कर रहे हैं इसका सम्मान करने के लिए।

लेकिन परिणाम गलत नहीं हैं, और यह कोई बग नहीं है। फ़ंक्शन वास्तव में कैसे काम करता है, इस बारे में अनजान लोगों के लिए यह एक "गॉचा" है।

ये सभी गोचा DATEDIFF_BIG() . पर भी लागू होते हैं समारोह। यह DATEDIFF() . की तरह ही काम करता है इस अपवाद के साथ कि यह परिणाम को हस्ताक्षरित बिगिंट . के रूप में लौटाता है (int . के विपरीत DATEDIFF() . के लिए )।

उदाहरण 4 - डेटा प्रकार पर निर्भर परिणाम

आप अपनी इनपुट तिथियों के लिए उपयोग किए जाने वाले डेटा प्रकार के कारण अप्रत्याशित परिणाम भी प्राप्त कर सकते हैं। इनपुट तिथियों के डेटा प्रकार के आधार पर परिणाम अक्सर भिन्न होंगे। लेकिन आप दोष नहीं दे सकते DATEDIFF() इसके लिए, क्योंकि यह विशुद्ध रूप से विभिन्न डेटा प्रकारों की क्षमताओं और सीमाओं के कारण है। आप कम सटीक इनपुट मान से उच्च परिशुद्धता परिणाम प्राप्त करने की अपेक्षा नहीं कर सकते।

उदाहरण के लिए, जब भी प्रारंभ तिथि या समाप्ति तिथि में छोटा दिनांक समय . हो मान, सेकंड और मिलीसेकंड हमेशा 0 लौटाएगा। ऐसा इसलिए है क्योंकि स्मॉलडेटटाइम डेटा प्रकार केवल मिनट के लिए सटीक है।

यदि हम उदाहरण 2 को smalldatetime . का उपयोग करने के लिए स्विच करते हैं, तो यहां क्या होता है? डेटाटाइम2 . के बजाय :

DECLARE @startdate smalldatetime = '2016-12-31 23:59:59', 
  @enddate smalldatetime = '2017-01-01 00:00:00';

SELECT DATEDIFF(year,     @startdate,   @enddate) Year,
  DATEDIFF(quarter,       @startdate,   @enddate) Quarter,
  DATEDIFF(month,         @startdate,   @enddate) Month,
  DATEDIFF(dayofyear,     @startdate,   @enddate) DOY,
  DATEDIFF(day,           @startdate,   @enddate) Day,
  DATEDIFF(week,          @startdate,   @enddate) Week,
  DATEDIFF(hour,          @startdate,   @enddate) Hour,
  DATEDIFF(minute,        @startdate,   @enddate) Minute,
  DATEDIFF(second,        @startdate,   @enddate) Second,
  DATEDIFF(millisecond,   @startdate,   @enddate) Millisecond,
  DATEDIFF(microsecond,   @startdate,   @enddate) Microsecond,
  DATEDIFF(nanosecond,    @startdate,   @enddate) Nanosecond;

परिणाम:

Year        | 0
Quarter     | 0
Month       | 0
DOY         | 0
Day         | 0
Week        | 0
Hour        | 0
Minute      | 0
Second      | 0
Millisecond | 0
Microsecond | 0
Nanosecond  | 0

इन सभी के शून्य होने का कारण यह है कि दोनों इनपुट तिथियां वास्तव में समान हैं:

DECLARE @startdate smalldatetime = '2016-12-31 23:59:59', 
  @enddate smalldatetime = '2017-01-01 00:00:00';
SELECT  
  @startdate 'Start Date',   
  @enddate 'End Date';

परिणाम:

+---------------------+---------------------+
| Start Date          | End Date            |
|---------------------+---------------------|
| 2017-01-01 00:00:00 | 2017-01-01 00:00:00 |
+---------------------+---------------------+

स्मॉलडेटटाइम . की सीमाएं डेटा प्रकार के कारण सेकंड को गोल किया जाता है, जिसके कारण प्रभाव पर प्रवाह होता है और सब कुछ गोल हो जाता है। यहां तक ​​​​कि अगर आप समान इनपुट मानों के साथ समाप्त नहीं होते हैं, तब भी आपको एक अप्रत्याशित परिणाम मिल सकता है क्योंकि डेटा प्रकार आपको आवश्यक सटीकता प्रदान नहीं करता है।


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. डिस्क I/O बाधाओं का निवारण करें

  2. मैं स्थानीय ड्राइव पर दूरस्थ SQL सर्वर डेटाबेस का बैकअप कैसे ले सकता हूं?

  3. एक कॉलम पर DISTINCT चुनें

  4. SQL सर्वर (T-SQL) में दिनांक और समय कार्यों की सूची

  5. SQL सर्वर 2017 में एक डेटाबेस को पुनर्स्थापित करें