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

जब भी मैं IsDate() का उपयोग करता हूं, तब भी मैं एक कास्ट डेटाटाइम पर फ़िल्टर करते समय अंकगणित अतिप्रवाह प्राप्त करता हूं

SQL सर्वर का DateTime डोमेन है 1753-01-01 00:00:00.000 ≤ x ≤ 9999-12-31 23:59:59.97। वर्ष 210 सीई उस डोमेन से बाहर है। इसलिए समस्या।

यदि आप SQL Server 2008 या बाद के संस्करण का उपयोग कर रहे थे, तो आप इसे DateTime2 . पर डाल सकते हैं डेटाटाइप और आप सुनहरे होंगे (इसका डोमेन 0001-01-01 00:00:00.0000000 &le x है 9999-12-31 23:59:59.99999999। लेकिन SQL सर्वर 2005 के साथ, आप काफी हद तक SOL हैं।

यह वास्तव में डेटा सफाई की समस्या है। इस तरह के मामलों में मेरा झुकाव तीसरे पक्ष के डेटा को एक स्टेजिंग टेबल में प्रत्येक फ़ील्ड के साथ चरित्र स्ट्रिंग के रूप में लोड करना है। फिर डेटा को जगह में साफ करें, उदाहरण के लिए, NULL के साथ अमान्य तिथियों की जगह। एक बार साफ हो जाने के बाद, इसे अपने अंतिम गंतव्य तक ले जाने के लिए आवश्यक रूपांतरण कार्य करें।

दूसरा तरीका यह है कि पैटर्न मिलान का उपयोग करें और datetime . में कुछ भी परिवर्तित किए बिना दिनांक फ़िल्टरिंग करें . आईएसओ 8601 दिनांक/समय मान वर्ण स्ट्रिंग हैं जिनमें (ए) मानव-पठनीय और (बी) ठीक से मिलान और तुलना करने की प्रशंसनीय संपत्ति है।

मैंने अतीत में जो कुछ किया है, वह कुछ विश्लेषणात्मक कार्य है जो दशमलव अंकों को 'd' से बदलकर और फिर group by चलाकर डेटाटाइम फ़ील्ड में सभी पैटर्न की पहचान करने के लिए है। पाए गए प्रत्येक अलग पैटर्न की गणना करने के लिए। एक बार आपके पास यह हो जाने के बाद आप मार्गदर्शन करने के लिए कुछ पैटर्न टेबल बना सकते हैं। कुछ इस तरह:

create table #datePattern
(
  pattern varchar(64) not null primary key clustered ,
  monPos  int         not null ,
  monLen  int         not null ,
  dayPos  int         not null ,
  dayLen  int         not null ,
  yearPos int         not null ,
  yearLen int         not null ,
)

insert #datePattern values ( '[0-9]/[0-9]/[0-9] %'                          ,1,1,3,1,5,1)
insert #datePattern values ( '[0-9]/[0-9]/[0-9][0-9] %'                     ,1,1,3,1,5,2)
insert #datePattern values ( '[0-9]/[0-9]/[0-9][0-9][0-9] %'                ,1,1,3,1,5,3)
insert #datePattern values ( '[0-9]/[0-9]/[0-9][0-9][0-9][0-9] %'           ,1,1,3,1,5,4)
insert #datePattern values ( '[0-9]/[0-9][0-9]/[0-9] %'                     ,1,1,3,2,6,1)
insert #datePattern values ( '[0-9]/[0-9][0-9]/[0-9][0-9] %'                ,1,1,3,2,6,2)
insert #datePattern values ( '[0-9]/[0-9][0-9]/[0-9][0-9][0-9] %'           ,1,1,3,2,6,3)
insert #datePattern values ( '[0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %'      ,1,1,3,2,6,4)
insert #datePattern values ( '[0-9][0-9]/[0-9]/[0-9] %'                     ,1,2,4,1,6,1)
insert #datePattern values ( '[0-9][0-9]/[0-9]/[0-9][0-9] %'                ,1,2,4,1,6,2)
insert #datePattern values ( '[0-9][0-9]/[0-9]/[0-9][0-9][0-9] %'           ,1,2,4,1,6,3)
insert #datePattern values ( '[0-9][0-9]/[0-9]/[0-9][0-9][0-9][0-9] %'      ,1,2,4,1,6,4)
insert #datePattern values ( '[0-9][0-9]/[0-9][0-9]/[0-9] %'                ,1,2,4,2,7,1)
insert #datePattern values ( '[0-9][0-9]/[0-9][0-9]/[0-9][0-9] %'           ,1,2,4,2,7,2)
insert #datePattern values ( '[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9] %'      ,1,2,4,2,7,3)
insert #datePattern values ( '[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] %' ,1,2,4,2,7,4)

create table #timePattern
(
  pattern varchar(64) not null primary key clustered ,
  hhPos int not null ,
  hhLen int not null ,
  mmPos int not null ,
  mmLen int not null ,
  ssPos int not null ,
  ssLen int not null ,
)
insert #timePattern values ( '[0-9]:[0-9]:[0-9]'                ,1,1,3,1,5,1 )
insert #timePattern values ( '[0-9]:[0-9]:[0-9][0-9]'           ,1,1,3,1,5,2 )
insert #timePattern values ( '[0-9]:[0-9][0-9]:[0-9]'           ,1,1,3,2,6,1 )
insert #timePattern values ( '[0-9]:[0-9][0-9]:[0-9][0-9]'      ,1,1,3,2,6,2 )
insert #timePattern values ( '[0-9][0-9]:[0-9]:[0-9]'           ,1,2,4,1,6,1 )
insert #timePattern values ( '[0-9][0-9]:[0-9]:[0-9][0-9]'      ,1,2,4,1,6,2 )
insert #timePattern values ( '[0-9][0-9]:[0-9][0-9]:[0-9]'      ,1,2,4,2,7,1 )
insert #timePattern values ( '[0-9][0-9]:[0-9][0-9]:[0-9][0-9]' ,1,2,4,2,7,2 )

आप इन दो तालिकाओं को 1 में जोड़ सकते हैं लेकिन संयोजनों की संख्या चीजों को विस्फोट कर देती है, हालांकि यह तब क्वेरी को बहुत सरल बनाती है।

एक बार आपके पास यह हो जाने के बाद, क्वेरी [काफी] आसान है, यह देखते हुए कि SQL स्ट्रिंग प्रोसेसिंग के लिए दुनिया की सबसे अच्छी भाषा पसंद नहीं है:

---------------------------------------------------------------------
-- first, get your lower bound in ISO 8601 format yyyy-mm-dd hh:mm:ss
-- This will compare/collate properly
---------------------------------------------------------------------
declare @dtLowerBound varchar(255)
set @dtLowerBound = convert(varchar,dateadd(year,-1,current_timestamp),121)

-----------------------------------------------------------------
-- select rows with a start date more recent than the lower bound
-----------------------------------------------------------------
select isoDate =       + right( '0000' + substring( t.startDate , coalesce(dt.yearPos,1) , coalesce(dt.YearLen,0) ) , 4 )
                 + '-' + right(   '00' + substring( t.startDate , coalesce(dt.monPos,1)  , coalesce(dt.MonLen,0)  ) , 2 )
                 + '-' + right(   '00' + substring( t.startDate , coalesce(dt.dayPos,1)  , coalesce(dt.dayLen,0)  ) , 2 )
                 + case
                   when tm.pattern is not null then
                       ' ' + right( '00' + substring(ltrim(rtrim( substring(t.startDate,dt.YearPos+dt.YearLen,1+len(t.startDate)-(dt.YearPos+dt.YearLen) ) ) ), tm.hhPos , tm.hhLen ) , 2 )
                     + ':' + right( '00' + substring(ltrim(rtrim( substring(t.startDate,dt.YearPos+dt.YearLen,1+len(t.startDate)-(dt.YearPos+dt.YearLen) ) ) ), tm.mmPos , tm.mmLen ) , 2 )
                     + ':' + right( '00' + substring(ltrim(rtrim( substring(t.startDate,dt.YearPos+dt.YearLen,1+len(t.startDate)-(dt.YearPos+dt.YearLen) ) ) ), tm.ssPos , tm.ssLen ) , 2 )
                   else ''
                   end
,*
from someTableWithBadData t
left join #datePattern dt on t.startDate like dt.pattern
left join #timePattern tm on ltrim(rtrim( substring(t.startDate,dt.YearPos+dt.YearLen,1+len(t.startDate)-(dt.YearPos+dt.YearLen) ) ) )
                             like tm.pattern
where @lowBound <=        + right( '0000' + substring( t.startDate , coalesce(dt.yearPos,1) , coalesce(dt.YearLen,0) ) , 4 )
                 + '-' + right(   '00' + substring( t.startDate , coalesce(dt.monPos,1)  , coalesce(dt.MonLen,0)  ) , 2 )
                 + '-' + right(   '00' + substring( t.startDate , coalesce(dt.dayPos,1)  , coalesce(dt.dayLen,0)  ) , 2 )
                 + case
                   when tm.pattern is not null then
                       ' ' + right( '00' + substring(ltrim(rtrim( substring(t.startDate,dt.YearPos+dt.YearLen,1+len(t.startDate)-(dt.YearPos+dt.YearLen) ) ) ), tm.hhPos , tm.hhLen ) , 2 )
                     + ':' + right( '00' + substring(ltrim(rtrim( substring(t.startDate,dt.YearPos+dt.YearLen,1+len(t.startDate)-(dt.YearPos+dt.YearLen) ) ) ), tm.mmPos , tm.mmLen ) , 2 )
                     + ':' + right( '00' + substring(ltrim(rtrim( substring(t.startDate,dt.YearPos+dt.YearLen,1+len(t.startDate)-(dt.YearPos+dt.YearLen) ) ) ), tm.ssPos , tm.ssLen ) , 2 )
                   else ''
                   end

जैसा मैंने कहा, SQL स्ट्रिंग्स को मंगने के लिए सबसे अच्छा विकल्प नहीं है।

यह आपको मिलना चाहिए ... 90% वहाँ। अनुभव मुझे बताता है कि आपको अभी भी अधिक खराब तिथियां मिलेंगी:महीने 1 से कम या 12 से अधिक, 1 से कम या 31 से अधिक दिन, या उस महीने के लिए सीमा से बाहर के दिन (कंप्यूटर को बेहतर बनाने के लिए 31 फरवरी जैसा कुछ नहीं) , आदि। विशेष रूप से पुराने कोबोल प्रोग्राम, लापता डेटा को इंगित करने के लिए सभी 9s के क्षेत्र का उपयोग करना पसंद करते थे, उदाहरण के लिए (हालांकि यह एक आसान मामला है)।

मेरी पसंदीदा तकनीक डेटा को साफ़ करने के लिए एक पर्ल स्क्रिप्ट लिखना है और इसे पर्ल की बीसीपी सुविधाओं का उपयोग करके SQL सर्वर में थोक लोड करना है। ठीक इसी तरह की समस्या स्पेस पर्ल के लिए डिज़ाइन की गई है।




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. कैसे पता करें कि कौन से कॉलम में कोई डेटा नहीं है (सभी मान NULL हैं)?

  2. किसी तारीख के लिए किसी नाम के रूप में राशि (col2) कैसे प्राप्त करें, (col2 * col3)/योग (col2) किसी तारीख के लिए somename1 के रूप में

  3. मैं फ्रीटीडीएस और यूनिक्सोडबीसी का उपयोग करके SQL सर्वर से स्ट्रिंग्स को सही ढंग से स्वीकार करने के लिए pyodbc को कैसे कॉन्फ़िगर कर सकता हूं?

  4. टीएसक्यूएल:स्थानीय समय को यूटीसी में कैसे परिवर्तित करें? (एसक्यूएल सर्वर 2008)

  5. MSSQL2008 - Pyodbc - पिछला SQL एक प्रश्न नहीं था