سؤال

أنا أستخدم 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

.

وكبديل، يمكنك استخدام الأعمدة المحسوبة .

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top