题
我使用SQL语句中的DATEDIFF。我选择它,我需要在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
在我的程序员说,这是低效的(好像我调用该函数两次)。
所以两个问题。为什么不先声明工作?它是低效使用第二条语句做呢?
解决方案
您将无法访问在WHERE语句select语句定义的列,因为他们直到在那里已被执行之后产生的。
但你可以做到这一点。
select InitialSave from
(SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable) aTable
WHERE InitialSave <= 10
作为旁注 - 这基本上移动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)
什么都好。它现在的优化搜索的,这意味着有一个有效的 “搜索参数” - 使发动机的扫描的的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'
此现在有仅一个第二总的最大舍入误差,而不是两个(实际上,地板()操作)。请注意,您只能减去datetime
数据类型 - 减去一个date
或你将不得不转换为time
或使用其他方法来获得更好的精度(一大堆datetime
的,DateAdd
和其他可能的垃圾一DateDiff
值,或可能使用更高的精度的时间单位和分割)。
此原则计数更大的单位,例如数小时,数天或数月时是特别重要的。 DateDiff
的1 month
可以62天开(认为2013年7月1日 - 2013年8月31日)!
超越使其成为 “工作”,你需要使用一个索引
使用计算列与索引或带索引的视图,否则就会表扫描。当你得到足够的行,你会觉得慢扫描的疼痛!
计算列&指数:
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
。作为替代,可以使用计算列的。