Използване на DATEDIFF в T-SQL

Използвам 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

Програмистът в мен казва, че това е неефективно (изглежда, че извиквам функцията два пъти).

Така че два въпроса. Защо първото твърдение не работи? Неефективно ли е да го правите с помощта на втория израз?


person Josh Stodola    schedule 15.05.2009    source източник


Отговори (5)


Не можете да получите достъп до колони, дефинирани в оператора select в оператора where, защото те не се генерират, докато не бъде изпълнен.

Можете обаче да направите това

select InitialSave from 
(SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable) aTable
WHERE InitialSave <= 10

Като странична бележка - това по същество премества DATEDIFF в оператора where по отношение на мястото, където е дефинирано за първи път. Използването на функции върху колони в изрази where води до това, че индексите не се използват толкова ефективно и трябва да се избягва, ако е възможно, но ако трябва да използвате datediff, тогава трябва да го направите!

person Dan Fuller    schedule 15.05.2009
comment
Така че, ако избирам 20 колони в допълнение към това, ще трябва да ги ИЗБЕРЕМ и в двата оператора (вътрешен и външен), нали? Има ли по-добър начин? - person Josh Stodola; 15.05.2009
comment
Ако искате, можете просто да използвате select * на първия ред, вместо да изберете InitialSave, Col2, Col3 и т.н. - person Dan Fuller; 15.05.2009
comment
О, ах! Благодаря! удря се по главата - person Josh Stodola; 15.05.2009

Това също е валиден подход. Грег вече даде добър отговор. Обикновено бих препоръчал също така да обмислите използването на ориентирани към поток типове за големите типове (n/varchar/varbinary(max) и xml), но вие казвате, че сте на SQL2K, така че не се прилага).
person ErikE    schedule 15.05.2009
comment
Това е просто глупаво. Когато направих този коментар, не изглеждах надут, а всъщност се опитвах да бъда наистина полезен на някой, който може да не знае практическите ефекти от нещата, които описвах. Моля, прочетете отново написаното от мен: може би бях малко прекалено точен, но не и обиден? - person ErikE; 06.06.2009
comment
О... и -1 на моята заявка за по-добро представяне поради една-единствена дума, която не сте разбрали е... попълнете празното тук, но не е безплатно. Хей, човече, опитвах се да споделя каквото мога. - person ErikE; 06.06.2009

Освен да го накарате да „работи“, трябва да използвате индекс

използвайте изчислена колона с индекс или изглед с индекс, в противен случай ще сканирате таблица. когато получите достатъчно редове, ще почувствате БОЛКАТА от бавното сканиране!

изчислена колона и индекс:

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
person KM.    schedule 15.05.2009
comment
Създаването на индекси на изгледи не винаги е магическият куршум. Мисля, че ще откриете, че индексът в колоната EndTime ще работи достатъчно добре и няма да има допълнителни разходи за актуализация. Това се свежда малко до шаблона за актуализиране/избор. - person ErikE; 16.05.2009
comment
Това е наистина добър момент и използването на изчислена колона наистина зависи от данните и честотата на използваната колона. Ако таблицата, за която се използва колоната, е вероятно да е голяма (както в, милиони редове +) и въпросната колона е: 1. Ще се използва изключително често в общото изпълнение на приложението 2. Ще бъде да бъдат достъпни рядко са служители на изпълнително ниво, които изискват бърз достъп. Тогава трябва да се използва изчислената колона. В противен случай може да е по-добре да не го използвате и да не забавяте вашите вмъквания/актуализации. - person Dan Fuller; 17.05.2009

Трябва да използвате функцията вместо псевдонима на колоната - същото е с count(*) и т.н. PITA.

person Otávio Décio    schedule 15.05.2009
comment
Достатъчно интелигентен ли е да не преминава през едни и същи обширни изчисления многократно? съмнявам се. - person Josh Stodola; 15.05.2009

Като алтернатива можете да използвате изчислени колони.

person Khurram Aziz    schedule 15.05.2009