سؤال
أنا أستخدم DATEDIFF في عبارة SQL.أنا أحدده، وأحتاج إلى استخدامه في جملة WHERE أيضًا.هذا التصريح لا ينفع...
SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE InitialSave <= 10
ويعطي الرسالة: اسم العمود "InitialSave" غير صالح
ولكن هذا البيان يعمل بشكل جيد ...
SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE DATEDIFF(ss, BegTime, EndTime) <= 10
يقول المبرمج بداخلي أن هذا غير فعال (يبدو أنني أتصل بالوظيفة مرتين).
إذن سؤالان.لماذا لا يعمل البيان الأول؟هل من غير الفعال القيام بذلك باستخدام العبارة الثانية؟
المحلول
ولا يمكنك الوصول إلى الأعمدة المحددة في العبارة حدد في البيان حيث، لأنهم لم تولد إلا بعد تنفيذ أين.
ويمكنك القيام بذلك ولكن
select InitialSave from
(SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable) aTable
WHERE InitialSave <= 10
وكما sidenote - وهذا ينتقل أساسا DATEDIFF في بيان حيث من حيث حيث انها تعرف لأول مرة. باستخدام وظائف على أعمدة في حيث تسبب بيانات الأرقام القياسية للا أن تستخدم بكفاءة ويجب تجنبها إن أمكن، ولكن إذا كنت قد حصلت على استخدام datediff ثم عليك أن تفعل ذلك!
نصائح أخرى
ملحوظة: عندما كتبت هذه الإجابة في الأصل قلت إن الفهرس الموجود في أحد الأعمدة يمكن أن ينشئ استعلامًا يؤدي أداءً أفضل من الإجابات الأخرى (وذكر دان فولر).ومع ذلك، لم أكن أفكر بشكل صحيح بنسبة 100٪.الحقيقة هي أنه بدون عمود محسوب أو عرض مفهرس (مجسد)، سيتم إجراء فحص كامل للجدول مطلوب, ، لأن عمودين التاريخ الجاري مقارنتهما مأخوذان من نفس طاولة!
أعتقد أنه لا تزال هناك قيمة في المعلومات الواردة أدناه، وهي 1) إمكانية تحسين الأداء في الوضع الصحيح، كما هو الحال عندما تكون المقارنة بين أعمدة من جداول مختلفة، و2) تعزيز عادة مطوري SQL المتمثلة في اتباع أفضل الممارسات وإعادة التشكيل تفكيرهم في الاتجاه الصحيح.
جعل الظروف سارجابل
أفضل الممارسات التي أشير إليها هي نقل عمود واحد ليكون بمفرده على جانب واحد من عامل المقارنة، كما يلي:
SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM dbo.MyTable T
WHERE T.EndTime <= T.BegTime + '00:00:10'
كما قلت، لن يؤدي هذا إلى تجنب إجراء فحص على طاولة واحدة، ولكن في مثل هذه الحالة يمكن أن يحدث فرقًا كبيرًا:
SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM
dbo.BeginTime B
INNER JOIN dbo.EndTime E
ON B.BeginTime <= E.EndTime
AND B.BeginTime + '00:00:10' > E.EndTime
EndTime
هو في كلتا الحالتين الآن وحده على جانب واحد من المقارنة.على افتراض أن BeginTime
يحتوي الجدول على عدد أقل من الصفوف، و EndTime
يحتوي الجدول على فهرس في العمود EndTime
, ، سيكون أداء هذا أفضل بكثير من أي شيء يستخدم DateDiff(second, B.BeginTime, E.EndTime)
.إنه الآن sargable, ، مما يعني أن هناك "وسيطة بحث" صالحة - مثل المحرك عمليات المسح ال BeginTime
الجدول، فإنه يمكن يطلب داخل ال EndTime
طاولة.يلزم الاختيار الدقيق للعمود الذي يوجد بمفرده على جانب واحد من المشغل - وقد يكون الأمر يستحق التجربة عن طريق وضعه BeginTime
في حد ذاته عن طريق القيام ببعض الجبر للتبديل إلى AND B.BeginTime > E.EndTime - '00:00:10'
دقة DateDiff
ويجب أن أشير إلى ذلك أيضًا DateDiff
لا يعود انقضى الوقت، ولكن بدلا من ذلك يحسب عدد حدود عبرت.إذا تم الاتصال به DateDiff
باستخدام إرجاع الثواني 1
, ، قد يعني هذا 3 ms
الوقت المنقضي، أو قد يعني ذلك 1997 ms
!وهذا في الأساس دقة +- 1 وحدة زمنية.للحصول على دقة أفضل لـ +- 1/2 وحدة زمنية، قد ترغب في مقارنة الاستعلام التالي 0
ل EndTime - BegTime
:
SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
FROM MyTable
WHERE EndTime <= BegTime + '00:00:10'
يحتوي هذا الآن على خطأ تقريب أقصى يبلغ إجمالي ثانية واحدة فقط، وليس اثنتين (في الواقع، عملية Floor()).لاحظ أنه يمكنك فقط طرح datetime
نوع البيانات - لطرح أ date
أو أ time
القيمة التي يجب عليك التحويل إليها datetime
أو استخدم طرقًا أخرى للحصول على دقة أفضل (الكثير من DateAdd
, DateDiff
وربما غيرها من الأشياء غير المرغوب فيها، أو ربما باستخدام وحدة زمنية وتقسيم أعلى دقة).
هذا المبدأ مهم بشكل خاص عند حساب الوحدات الأكبر مثل الساعات أو الأيام أو الأشهر.أ DateDiff
ل 1 month
يمكن أن يفصل بينهما 62 يومًا (فكر في الفترة من 1 تموز (يوليو) 2013 إلى 31 آب (أغسطس) 2013)!
بعد جعله "يعمل"، تحتاج إلى استخدام فهرس
استخدم عمودًا محسوبًا مع فهرس، أو عرضًا به فهرس، وإلا فسوف تقوم بمسح الجدول.عندما تحصل على ما يكفي من الصفوف، سوف تشعر ألم من الفحص البطيء!
العمود والفهرس المحسوب:
ALTER TABLE MyTable ADD
ComputedDate AS DATEDIFF(ss,BegTime, EndTime)
GO
CREATE NONCLUSTERED INDEX IX_MyTable_ComputedDate ON MyTable
(
ComputedDate
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
إنشاء عرض وفهرس:
CREATE VIEW YourNewView
AS
SELECT
KeyValues
,DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
GO
CREATE CLUSTERED INDEX IX_YourNewView
ON YourNewView(InitialSave)
GO
لديك لاستخدام وظيفة بدلا من الاسم المستعار العمود - هو نفسه مع العد (*)، الخ PITA
.وكبديل، يمكنك استخدام الأعمدة المحسوبة .