2008-08-22 9 views
17

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

इस मामले में, फ़ंक्शन कोड को वापस क्वेरी में विलय करना अव्यवहारिक लगता है।

मुझे लगता है कि मुझे यहां कुछ आसान याद आ रहा है।

यहां संदर्भ के लिए कार्य है।

where 
dbo.f_MakeDate(dateadd(hh, tz.Offset + 
    case when ds.LocalTimeZone is not null 
    then 1 else 0 end, t.TheDateINeedToCheck), 0, 0) = @activityDateMidnight 

[संपादित करें]

मैं:

if not exists (select * from dbo.sysobjects 
       where id = object_id(N'dbo.f_MakeDate') and    
       type in (N'FN', N'IF', N'TF', N'FS', N'FT')) 
    exec('create function dbo.f_MakeDate() returns int as 
     begin declare @retval int return @retval end') 
go 

alter function dbo.f_MakeDate 
(
    @Day datetime, 
    @Hour int, 
    @Minute int 
) 
returns datetime 
as 

/* 

Creates a datetime using the year-month-day portion of @Day, and the 
@Hour and @Minute provided 

*/ 

begin 

declare @retval datetime 
set @retval = cast(
    cast(datepart(m, @Day) as varchar(2)) + 
    '/' + 
    cast(datepart(d, @Day) as varchar(2)) + 
    '/' + 
    cast(datepart(yyyy, @Day) as varchar(4)) + 
    ' ' + 
    cast(@Hour as varchar(2)) + 
    ':' + 
    cast(@Minute as varchar(2)) as datetime) 
return @retval 
end 

go 

मामलों को मुश्किल करने के लिए, मैं स्थानीय समय के खिलाफ की तारीख की जाँच करने के, जो हर पंक्ति के लिए अलग-अलग हो सकता है समय क्षेत्र टेबल पर शामिल होने हूँ @ टोड के सुझाव को शामिल कर रहा हूं:

where datediff(day, dateadd(hh, tz.Offset + 
    case when ds.LocalTimeZone is not null 
    then 1 else 0 end, t.TheDateINeedToCheck), @ActivityDate) = 0 

मेरे बारे में गलतफहमी कैसे काम करती है (उसी दिन लगातार वर्षों में वर्ष 366 उत्पन्न होता है, जैसा कि मैंने अपेक्षित नहीं किया) ने मुझे बहुत सारे प्रयासों को बर्बाद कर दिया।

लेकिन क्वेरी योजना नहीं बदली। मुझे लगता है कि मुझे पूरी चीज के साथ ड्राइंग बोर्ड पर वापस जाने की जरूरत है।

+0

कृपया मार्क ब्रैकेट का जवाब देखें, जो ** सही ** एक है। मुझे एहसास है कि आपका प्रश्न 2 साल पुराना है, लेकिन कृपया इस सवाल पर जाने वाले गलत रास्ते से लोगों को नेतृत्व न करें। टोड टिंगन का जवाब काम करता है लेकिन उस समय आपको लगता है कि भयानक प्रदर्शन है! – ErikE

+0

मार्क का उत्तर इस स्थिति के लिए सही है क्योंकि अनुकूलक इस पर निर्भर करता है। जिस तरह से मैंने किया है डेटडैड का उपयोग करना एक सरल, संक्षिप्त तरीका है यह देखने के लिए कि क्या दो तिथियां उसी कैलेंडर दिन पर हैं, जो मूल प्रश्न था। – Todd

उत्तर

51

यह बहुत अधिक संक्षिप्त है:

where 
    datediff(day, date1, date2) = 0 
+6

इसमें 9 अप-वोट क्यों हैं और इसका उत्तर दिया गया था? यह संक्षेप में है, ठीक है, और ओपी को गलत रास्ते से नीचे ले गया। दूसरी तारीख के बाद से, एक्टिविटीडेट तय किया गया है, हम गणित को दाईं ओर ले जा सकते हैं और बेहतर प्रदर्शन प्राप्त कर सकते हैं। – ErikE

+2

@emtucifor के साथ सहमत हुए। यह तर्क एसक्यूएल सर्वर द्वारा सार योग्य नहीं है। – DForck42

+0

@ एरिक, मुझे आपका मतलब क्या नहीं है, क्या आपके पास कोड स्निपेट है? – Joyce

3
where 
year(date1) = year(date2) 
and month(date1) = month(date2) 
and day(date1) = day(date2) 
1

यह आपके लिए एक तारीख से समय घटक निकाल देगा:

select dateadd(d, datediff(d, 0, current_timestamp), 0) 
15

आप काफी के बाईं ओर रखने के लिए अपने जहां क्लॉज साफ तो, सामान्य रूप से, आप की तरह कुछ करना चाहते हैं:

WHERE MyDateTime >= @activityDateMidnight 
     AND MyDateTime < (@activityDateMidnight + 1) 

(कुछ लोगों को पसंद करते हैं DATEADD (घ, 1, @activityDateMidnight) के बजाय - लेकिन यह एक ही बात है)।

टाइमज़ोन तालिका कुछ मामलों को जटिल करती है। यह आपके स्निपेट से थोड़ा अस्पष्ट है, लेकिन ऐसा लगता है। डेटइनटेबल एक समय क्षेत्र पहचानकर्ता के साथ जीएमटी में है, और फिर आप @activityDateMidnight के खिलाफ तुलना करने के लिए ऑफ़सेट जोड़ रहे हैं - जो स्थानीय समय में है। मुझे यकीन नहीं है कि डॉ। लॉकटाइमज़ोन क्या है।

यदि ऐसा है, तो आपको इसके बजाय @activityDateMidnight को जीएमटी में प्राप्त करने की आवश्यकता है।

0

आप यहाँ विकल्प के मामले में चुनाव के लिए खराब हो रहे हैं के साथ खिलवाड़ सुनिश्चित करें कि अनुकूलक प्रभावी रूप से सूचकांक का उपयोग कर सकते हैं। यदि आप Sybase या SQL Server 2008 का उपयोग कर रहे हैं तो आप टाइप दिनांक के चर बना सकते हैं और उन्हें अपने डेटाटाइम मान असाइन कर सकते हैं। डेटाबेस इंजन आपके लिए समय से छुटकारा पाता है।आप क्या कर सकते एक प्रारूप उस समय घटक नहीं है में एक varchar करने के लिए तिथि परिवर्तित है

declare @date1 date 
declare @date2 date 
set @date1='2008-1-1 10:00' 
set @date2='2008-1-1 22:00' 
if @[email protected] 
    print 'Equal' 
else 
    print 'Not equal' 

एसक्यूएल 2005 के लिए और पहले: यहाँ वर्णन करने के लिए एक त्वरित और गंदा परीक्षण है (कोड Sybase बोली में है)। उदाहरण के लिए निम्नलिखित रिटर्न 2008.08.22

select convert(varchar,'2008-08-22 18:11:14.133',102) 

102 भाग (ऑनलाइन पुस्तकें सभी उपलब्ध प्रारूप है जिसे आप सूचीबद्ध कर सकते हैं) निर्दिष्ट स्वरूपण

तो, आप क्या कर सकते एक समारोह है कि एक लेता है लिखना है डेटाटाइम और दिनांक तत्व निकालता है और समय को त्याग देता है। इसलिए जैसा:

create function MakeDate (@InputDate datetime) returns datetime as 
begin 
    return cast(convert(varchar,@InputDate,102) as datetime); 
end 

फिर आप साथियों

Select * from Orders where dbo.MakeDate(OrderDate) = dbo.MakeDate(DeliveryDate) 
0

के लिए समारोह का उपयोग कर सकते मैं DatePart की dayofyear समारोह का प्रयोग करेंगे:


Select * 
from mytable 
where datepart(dy,date1) = datepart(dy,date2) 
and 
year(date1) = year(date2) --assuming you want the same year too 

DatePart संदर्भ here देखें।

0

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

2

एरिक जेड दाढ़ी:

मैं जीएमटी में सभी तिथियों की दुकान है। यहां उपयोग का मामला है: पहली बार 11:00 बजे ईएसटी पर कुछ हुआ, जो दूसरा जीएमटी है। मैं पहले के लिए गतिविधि देखना चाहता हूं, और मैं ईएसटी में हूं इसलिए मैं 11 पीएम गतिविधि देखना चाहता हूं। अगर मैंने कच्चे जीएमटी डेटाटाइम की तुलना की है, तो मैं चीजों को याद करता हूं। रिपोर्ट में प्रत्येक पंक्ति एक अलग समय क्षेत्र से एक गतिविधि का प्रतिनिधित्व कर सकते हैं।

ठीक है, लेकिन जब आप कहते हैं यदि आपने 1 जनवरी 2008 ईएसटी के लिए गतिविधि में रुचि रखते हैं:

SELECT @activityDateMidnight = '1/1/2008', @activityDateTZ = 'EST' 

तुम सिर्फ कि जीएमटी को (मैं क्वेरी करने की जटिलता की अनदेखी कर रहा हूँ बदलने की आवश्यकता

Table: TimeZone 
Fields: TimeZone, Offset 
Values: EST, -4 

--Multiply by -1, since we're converting EST to GMT. 
--Offsets are to go from GMT to EST. 
SELECT @activityGmtBegin = DATEADD(hh, Offset * -1, @activityDateMidnight) 
FROM TimeZone 
WHERE TimeZone = @activityDateTZ 

जो आप '2008/01/01 4:00 हूँ' देना चाहिए: एक दिन पहले ईएसटी EDT, या इसके विपरीत करने के लिए चला जाता है) के लिए। उसके बाद, आप बस जीएमटी खोज कर सकते हैं:

SELECT * FROM EventTable 
WHERE 
    EventTime >= @activityGmtBegin --1/1/2008 4:00 AM 
    AND EventTime < (@activityGmtBegin + 1) --1/2/2008 4:00 AM 

प्रश्न में घटना के 2008/01/02 3:00 AM एक जीएमटी EVENTTIME साथ संग्रहीत किया जाता है। आपको EventTable में टाइमज़ोन की भी आवश्यकता नहीं है (इस उद्देश्य के लिए, कम से कम)।

चूंकि EventTime फ़ंक्शन में नहीं है, यह एक सीधी अनुक्रमणिका स्कैन है - जो कि बहुत ही कुशल होना चाहिए। इवेंटटाइम को अपने क्लस्टर इंडेक्स बनाएं, और यह उड़ जाएगा। ;)

व्यक्तिगत रूप से, मैं ऐप को क्वेरी चलाने से पहले खोज समय को जीएमटी में परिवर्तित कर दूंगा।

1

एरिक जेड दाढ़ी:

गतिविधि तारीख स्थानीय समय क्षेत्र से संकेत मिलता है करने के लिए है, लेकिन एक एक

ठीक विशिष्ट नहीं - ड्राइंग बोर्ड पर वापस। इस प्रयास करें:

where t.TheDateINeedToCheck BETWEEN (
    dateadd(hh, (tz.Offset + ISNULL(ds.LocalTimeZone, 0)) * -1, @ActivityDate) 
    AND 
    dateadd(hh, (tz.Offset + ISNULL(ds.LocalTimeZone, 0)) * -1, (@ActivityDate + 1)) 
) 

जो स्थानीय समय में @ActivityDate अनुवाद करेगा, और उस के खिलाफ की तुलना करें। यह इंडेक्स का उपयोग करने का आपका सबसे अच्छा मौका है, हालांकि मुझे यकीन नहीं है कि यह काम करेगा - आपको इसे आजमाएं और क्वेरी प्लान की जांच करनी चाहिए।

अगला विकल्प एक अनुक्रमित, अनुक्रमित टाइमइनिड टॉशेक स्थानीय समय में अनुक्रमित दृश्य होगा। - हालांकि आप सम्मिलित करें और अद्यतन पर एक मामूली भूमि के ऊपर तो है

where v.TheLocalDateINeedToCheck BETWEEN @ActivityDate AND (@ActivityDate + 1) 

जो निश्चित रूप से सूचकांक का प्रयोग करेंगे: तो फिर तुम बस वापस करने के लिए जाना।

संबंधित मुद्दे

 संबंधित मुद्दे