मेरी क्वेरी खोज डेटाइम मेल क्यों नहीं करती है?


20
select * 
from A 
where posted_date >= '2015-07-27 00:00:00.000' 
  and posted_date  <= '2015-07-27 23:59:59.999'

लेकिन परिणाम में एक रिकॉर्ड है जो आज पोस्ट किया गया है: 2015-07-28। मेरा डेटाबेस सर्वर मेरे देश में नहीं है। समस्या क्या है ?

जवाबों:


16

चूँकि आप datetimeडेटाटाइप का उपयोग कर रहे हैं , आपको यह समझने की आवश्यकता है कि SQL सर्वर डेटाटाइम को कैसे राउंड करता है।

╔═══════════╦═════╦═════════════════════════════╦═════════════════════════════╦══════════╦═══════════╗
   Name     sn          Minimum value                Maximum value         Accuracy   Storage  
╠═══════════╬═════╬═════════════════════════════╬═════════════════════════════╬══════════╬═══════════╣
 datetime   dt   1753-01-01 00:00:00.000      9999-12-31 23:59:59.997      3.33 ms   8 bytes   
 datetime2  dt2  0001-01-01 00:00:00.0000000  9999-12-31 23:59:59.9999999  100ns     6-8 bytes 
╚═══════════╩═════╩═════════════════════════════╩═════════════════════════════╩══════════╩═══════════╝

यहाँ छवि विवरण दर्ज करें

नीचे क्वेरी का उपयोग करके, आप DATETIMEडेटा प्रकार का उपयोग करते समय आसानी से उस sql सर्वर को गोल करने की समस्या देख सकते हैं ।

select  '2015-07-27 00:00:00.000'                       as Original_startDateTime,
        convert(datetime ,'2015-07-27 00:00:00.000')    as startDateTime,
        '2015-07-27 23:59:59.999'                       as Original_endDateTime,
        convert(datetime ,'2015-07-27 23:59:59.999')    as endDateTime,
        '2015-07-27 00:00:00.000'                       as Original_startDateTime2,
        convert(datetime2 ,'2015-07-27 00:00:00.000')   as startDateTime2,  -- default precision is 7
        '2015-07-27 23:59:59.999'                       as Original_endDateTime2,
        convert(datetime2 ,'2015-07-27 23:59:59.999')   as endDateTime2     -- default precision is 7

यहाँ छवि विवरण दर्ज करें बड़ा करने के लिए क्लिक करें

DATETIME2SQL Server 2008 के बाद से चारों ओर है, इसलिए इसके बजाय इसका उपयोग करना शुरू करें DATETIME। अपनी स्थिति के लिए, आप उपयोग कर सकते हैं datetime2के साथ 3 दशमलव की परिशुद्धता जैसे datetime2(3)

उपयोग करने के लाभ datetime2:

  • समय घटक के लिए 7 दशमलव स्थानों का समर्थन करता है बनाम datetimeकेवल 3 दशमलव स्थानों का समर्थन करता है .. और इसलिए आप गोल datetimeचक्कर को डिफ़ॉल्ट रूप से देखते हैं , या सेकंड के .003 secondsवेतन वृद्धि के साथ निकटतम ।.000.003.007
  • datetime2की तुलना में बहुत अधिक सटीक है datetimeऔर datetime2आपको नियंत्रण देता है DATEऔर इसके TIMEविपरीत datetime

संदर्भ:


1
gives you control of DATE and TIME as opposed to datetime.इसका क्या मतलब है?
नुरेटिन

पुन। का उपयोग कर DateTime2बनाम DateTime: ए। के लिए - विशाल - बहुसंख्यक - का - वास्तविक - दुनिया का उपयोग करें - मामलों, DateTime2ज्यादा <लागतों का लाभ । देखें: stackoverflow.com/questions/1334143/… b। यही कारण है कि नहीं है जड़ समस्या यहाँ। अगली टिप्पणी देखें
टॉम

यहां मूल समस्या (जैसा कि मैं शर्त लगाता हूं कि अधिकांश वरिष्ठ देव सहमत होंगे) एक तारीख-समय सीमा की तुलना की समावेशी समाप्ति तिथि-समय में अपर्याप्त परिशुद्धता नहीं है, बल्कि एक समावेशी (बनाम अनन्य) एक अवधि का उपयोग है। यह पाई की समानता की जाँच करने जैसा है, वहाँ हमेशा संभावना है कि #s में से एक है> या <परिशुद्धता (यानी क्या होगा यदि datetime370 (बनाम 7) के साथ सटीक जोड़ा गया अंक?)। सबसे अच्छा अभ्यास एक ऐसे मूल्य का उपयोग करना है जहां परिशुद्धता मायने नहीं रखती है, << अगले दूसरे की शुरुआत , मिनट, घंटे या दिन बनाम <= पहले दूसरे, मिनट, घंटे या दिन का अंत
टॉम

18

जैसा कि कई अन्य लोगों ने टिप्पणियों में उल्लेख किया है और आपके प्रश्न के अन्य उत्तरों में मुख्य मुद्दा SQL सर्वर द्वारा 2015-07-27 23:59:59.999गोल किया जा रहा है 2015-07-28 00:00:00.000प्रलेखन के लिए प्रतिDATETIME :

समय सीमा - 00:00:00 23: 59: 59.997 के माध्यम से

ध्यान दें कि समय सीमा कभी नहीं हो सकती .999। प्रलेखन में और नीचे यह गोलाई नियमों को निर्दिष्ट करता है जो SQL सर्वर कम से कम महत्वपूर्ण अंक के लिए उपयोग करता है।

गोल नियम दिखाने वाली तालिका

ध्यान दें कि कम से कम महत्वपूर्ण अंक में केवल तीन संभावित मान हो सकते हैं: "0", "3", या "7"।

इसके लिए कई समाधान / समाधान हैं जो आप उपयोग कर सकते हैं।

-- Option 1
SELECT 
    * 
FROM A 
WHERE posted_date >= '2015-07-27 00:00:00.000' 
  AND posted_date <  '2015-07-28 00:00:00.000' --Round up and remove equality

-- Option 2
SELECT 
    * 
FROM A 
WHERE posted_date >= '2015-07-27 00:00:00.000' 
  AND posted_date <=  '2015-07-27 23:59:59.997' --Round down and keep equality

-- Option 3
SELECT 
    * 
FROM A 
WHERE CAST(posted_date AS DATE) = '2015-07-27' -- Use different data type

-- Option 4
SELECT 
    * 
FROM A 
WHERE CONVERT(CHAR(8), DateColumn, 112) = '20150727' -- Cast to string stripping off time

-- Option 5
SELECT 
    * 
FROM A 
WHERE posted_date BETWEEN '2015-07-27 00:00:00.000' 
  AND '2015-07-27 23:59:59.997' --Use between

मैंने जिन पाँच विकल्पों के ऊपर प्रस्तुत किया है उनमें से मैं विकल्प 1 और 3 को ही व्यवहार्य विकल्प मानूंगा। वे आपके इरादे को स्पष्ट रूप से व्यक्त करते हैं, और यदि आप डेटा प्रकारों को अपडेट करते हैं तो वे टूटने वाले नहीं हैं। यदि आप SQL Server 2008 या नए का उपयोग कर रहे हैं तो मुझे लगता है कि विकल्प 3 आपका पसंदीदा तरीका होना चाहिए। यही कारण है कि विशेष रूप से सच है अगर आप का उपयोग करने से दूर बदल सकते हैं DATETIMEएक करने के लिए डेटाप्रकार DATEअपने लिए डेटा प्रकार posted_dateस्तंभ।

विकल्प 3 के बारे में, कुछ मुद्दों के बारे में बहुत अच्छी व्याख्या यहां पाई जा सकती है: कास्ट डेट टू सर्जेबल है लेकिन क्या यह एक अच्छा विचार है?

मुझे विकल्प 2 और 5 पसंद नहीं है क्योंकि .997भिन्नात्मक सेकंड केवल एक और जादुई संख्या होने जा रही है जिसे लोग "ठीक" करना चाहते हैं। कुछ और कारणों BETWEENसे आप इस पोस्ट को चेकआउट नहीं करना चाहते हैं ।

मुझे विकल्प 4 पसंद नहीं है क्योंकि तुलनात्मक उद्देश्यों के लिए डेटा प्रकारों को एक स्ट्रिंग में परिवर्तित करना मुझे गंदा लगता है। SQL सर्वर में इससे बचने का एक और गुणात्मक कारण यह है कि यह sargability उर्फ को प्रभावित करता है जिसे आप अनुक्रमणिका की तलाश नहीं कर सकते हैं और जिसके परिणामस्वरूप अक्सर खराब प्रदर्शन होगा।

डेट रेंज प्रश्नों को संभालने के सही तरीके और गलत तरीके के बारे में अधिक जानकारी के लिए आरोन बर्ट्रेंड द्वारा इस पोस्ट की जांच करें

अलग में आप और आपकी मूल क्वेरी रखने के लिए सक्षम हो जाएगा इसलिए अगर आप अपने अपने को बदलने वांछित के रूप में व्यवहार होता posted_dateएक से स्तंभ DATETIMEएक करने के लिए DATETIME2(3)। यह सर्वर पर स्टोरेज स्पेस को बचाएगा, आपको एक ही परिशुद्धता पर अधिक सटीकता देगा, अधिक मानकों का अनुपालन / पोर्टेबल हो सकता है, और यदि भविष्य में आपकी ज़रूरतें बदलती हैं तो आप सटीकता / सटीकता को आसानी से समायोजित कर सकते हैं। हालाँकि, यह केवल एक विकल्प है यदि आप SQL Server 2008 या नए का उपयोग कर रहे हैं।

इस स्टैकऑवरफ्लो उत्तर के प्रति UNIX से पकड़ के 1/300साथ एक दूसरी सटीकता के एक सामान्य ज्ञान के रूप में । साइबेस के पास एक साझा विरासत है जो उनके और डेटा प्रकारों में एक दूसरी सटीकता के समान है लेकिन उनके कम से कम महत्वपूर्ण अंक "0", "3" और "6" पर एक स्पर्श भिन्न हैं। मेरी राय में एक दूसरे और / या 3.33ms सटीकता का एक दुर्भाग्यपूर्ण वास्तुशिल्प निर्णय है क्योंकि SQL सर्वर के डेटा प्रकार में 4 बाइट ब्लॉक आसानी से 1ms सटीकता का समर्थन कर सकता है।DATETIME1/300DATETIMETIME1/300DATETIME


हां, लेकिन मुख्य "कोर इश्यू" विकल्प 1 का उपयोग नहीं कर रहा है (जैसे किसी भी समावेशी (बनाम अनन्य) रेंज अंत मूल्य का उपयोग करना जहां अतीत या संभावित भविष्य के डेटा प्रकारों की सटीकता परिणाम परिणाम ला सकती है)। यह पाई की समानता की जांच करने जैसा है, यह हमेशा संभव है कि एक # है> या <परिशुद्धता (जब तक कि दोनों सबसे आम सामान्य परिशुद्धता के लिए पूर्व-गोल न हों)। क्या होगा अगर datetime3परिशुद्धता के 70 (बनाम 7) अंकों के साथ? सबसे अच्छा अभ्यास एक ऐसे मूल्य का उपयोग करना है जहां परिशुद्धता मायने नहीं रखती है, <<अगले दूसरे की शुरुआत, मिनट, घंटे या दिन बनाम <= पहले दूसरे, मिनट, घंटे या दिन का अंत।
टॉम

9

अव्यवस्थित रूपांतरण

मेरा मानना ​​है कि पोस्ट किया गया_डेट डेटा प्रकार डेटाटाइम है। हालांकि इससे कोई फर्क नहीं पड़ता कि दूसरी तरफ का टाइप डेटाइम, डेटाटाइम 2 या सिर्फ टाइम है क्योंकि स्ट्रिंग (वर्चर) को कथित तौर पर डेटाटाइम में बदल दिया जाएगा।

Post_date को एक डाइमटाइम 2 (या समय) के रूप में घोषित करने के साथ, posted_date <= '2015-07-27 23:59:59.99999'जहां क्लॉज विफल हो जाता है क्योंकि 23:59:59.99999पूरी तरह से वैध डेटटाइम 2 मान है, यह मान्य डेटटाइम मान नहीं है:

 Conversion failed when converting date and/or time from character string.

टाइमटाइम के लिए समय सीमा

डेटाइम की समय सीमा 23: 59: 59.997 के माध्यम से 00:00:00 है। इसलिए 23: 59: 59.999 सीमा से बाहर है और इसे निकटतम मूल्य के लिए ऊपर या नीचे गोल करना पड़ता है।

शुद्धता

इसके अलावा .टाइम मूल्यों को .000, .003, या .007 सेकंड की वेतन वृद्धि द्वारा राउंड किया जाता है। (अर्थात। 000, 003, 007, 010, 013, 017, 020, ..., 997)

यह मान के साथ ऐसा नहीं है 2015-07-27 23:59:59.999जो इस सीमा के भीतर है: 2015-07-27 23:59:59.997और 2015-07-28 0:00:00.000

यह सीमा निकटतम पूर्ववर्ती और निम्नलिखित विकल्पों के अनुरूप है, दोनों को .000, .003 या .007 के साथ समाप्त होता है।

ऊपर या नीचे गोलाई ?

क्योंकि यह 2015-07-28 0:00:00.000(+1 बनाम -2) की तुलना में करीब है 2015-07-27 23:59:59.997, स्ट्रिंग को गोल किया गया है और यह डेटाटाइम मान बन गया है 2015-07-28 0:00:00.000:।

एक ऊपरी सीमा जैसे 2015-07-27 23:59:59.998(या .995, .996, .997, .998) के साथ, यह राउंड डाउन हो जाता था 2015-07-27 23:59:59.997और आप क्वेरी उम्मीद के मुताबिक काम करते थे। हालांकि यह एक समाधान नहीं है, लेकिन सिर्फ एक भाग्यशाली मूल्य होगा।

डेटाटाइम 2 या समय प्रकार

डेटाटाइम 2 और समय समय सीमाएं 100ns की सटीकता (अंतिम अंक जब 7 अंकों की सटीकता के साथ उपयोग की जाती हैं) के 00:00:00.0000000माध्यम से होती हैं 23:59:59.9999999

हालाँकि एक डेटटाइम (3) रेंज डेटाइम रेंज के समान नहीं है:

  • datetime 0:0:00.000करने के लिए23:59:59.997
  • डेटाटाइम 2 0:0:00.000000000से23:59:59.999

समाधान

अंत में, यह अगले दिन से नीचे की तारीखों की तुलना में नीचे की तारीखों को देखने के लिए सुरक्षित है या आप इसे दिन के समय का अंतिम टुकड़ा मानते हैं। यह मुख्य रूप से है क्योंकि आप जानते हैं कि अगले दिन हमेशा 0: 00: 00.000 से शुरू होता है, लेकिन विभिन्न डेटा प्रकारों का दिन के अंत में एक ही समय नहीं हो सकता है:

Datetime `0:0:00.000` to `23:59:59.997`
Datetime2 `0:0:00.000000000` to `23:59:59.999-999-900`
Time2 `0:0:00.000000000` to `23:59:59.999-999-900`
  • < 2015-07-28 0:00:00.000आपको एक सटीक परिणाम देगा और सबसे अच्छा विकल्प है
  • <= 2015-07-27 23:59:59.xxx जब आप सोचते हैं कि यह होना चाहिए तो यह गोल नहीं होने पर अप्रत्याशित मान लौटा सकता है।
  • तिथि में परिवर्तन और फ़ंक्शन के उपयोग से बचा जाना चाहिए क्योंकि यह अनुक्रमित के उपयोग को सीमित करता है

हम सोच सकते हैं कि [पोस्ट_डेट] को बदलकर डाटटाइम 2 और इसकी उच्च परिशुद्धता इस समस्या को ठीक कर सकती है लेकिन यह मदद नहीं करेगा क्योंकि स्ट्रिंग अभी भी डाटटाइम में परिवर्तित है। हालाँकि, यदि कोई कलाकार जोड़ा जाता है cast(2015-07-27 23:59:59.999' as datetime2), तो यह ठीक काम करता है

कास्ट और कन्वर्ट

कास्ट एक मान को 3 अंकों तक डेटाटाइम में या 9 अंकों के साथ डेटाटाइम 2 या समय में बदल सकता है और इसे सही सटीकता के लिए राउंड कर सकता है।

यह ध्यान दिया जाना चाहिए कि डेटाटाइम 2 और टाइम 2 के कास्ट अलग परिणाम दे सकते हैं:

  • select cast('20150101 23:59:59.999999999' as datetime2(7)) 2015-05-03 00: 00: 00.0000000 (999999949 से अधिक मूल्य के लिए) का राउंड अप है
  • select cast('23:59:59.999999999' as time(7)) => 23: 59: 59.9999999

यह 0, 3 और 7 वेतन वृद्धि के साथ होने वाली समस्या को ठीक करने का एक प्रकार है, हालांकि अगले दिन के 1 नैनो सेकंड (हमेशा 0: 00: 00.000) से पहले तारीखों की तलाश करना हमेशा बेहतर होता है।

स्रोत MSDN: डेटाइम (Transact-SQL)


6

यह गोलाई है

 select cast('2015-07-27 23:59:59.999' as datetime) 
 returns 2015-07-28 00:00:00.000

.998, .997, .996, .995 सभी डाली / .997 को राउंड

उपयोग करना चाहिए

select * 
from A 
where posted_date >= '2015-07-27 00:00:00.000' 
  and posted_date <  '2015-07-28 00:00:00.000'

या

where cast(posted_date as date) = '2015-07-27'

इस लिंक में सटीकता
हमेशा देखें .000, .003, .007 के रूप में रिपोर्ट किया गया


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.