在 T-SQL 中使用 DATEDIFF
我在 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
我的程序员说这是低效的(似乎我正在调用函数两次)。
那么两个问题。 为什么第一个语句不起作用? 使用第二个语句执行此操作是否效率低下?
I am using DATEDIFF in an SQL statement. I am selecting it, and I need to use it in WHERE clause as well. This statement does not work...
SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE InitialSave <= 10
It gives the message: Invalid column name "InitialSave"
But this statement works fine...
SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE DATEDIFF(ss, BegTime, EndTime) <= 10
The programmer in me says that this is inefficient (seems like I am calling the function twice).
So two questions. Why doesn't the first statement work? Is it inefficient to do it using the second statement?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
除了使其“工作”之外,您还需要使用索引
使用带有索引的计算列或带有索引的视图,否则您将进行表扫描。 当你获得足够多的行时,你会感受到慢速扫描的痛苦!
计算列和 索引:
创建视图& 指数:
beyond making it "work", you need to use an index
use a computed column with an index, or a view with an index, otherwise you will table scan. when you get enough rows, you will feel the PAIN of the slow scan!
computed column & index:
create a view & index:
您必须使用该函数而不是列别名 - 它与 count(*) 等相同。PITA。
You have to use the function instead of the column alias - it is the same with count(*), etc. PITA.
作为替代方案,您可以使用计算列。
As an alternate, you can use computed columns.
注意:当我最初写这个答案时,我说过其中一列上的索引可以创建一个比其他答案性能更好的查询(并提到了 Dan Fuller 的答案)。 然而,我的想法并不是100%正确。 事实是,如果没有计算列或索引(物化)视图,则需要进行全表扫描,因为要比较的两个日期列来自相同的日期列桌子!
我相信下面的信息仍然有价值,即1)在正确的情况下提高性能的可能性,例如在不同表的列之间进行比较时,2)促进SQL开发人员遵循最佳实践和重塑的习惯他们的思维方向是正确的。
使条件可控制
我指的最佳实践是将一列移动到比较运算符的一侧,如下所示:
正如我所说,这不会避免对但是,在这种情况下,单个表可能会产生巨大的差异:
在这两种情况下,EndTime 现在都单独位于比较的一侧。 假设
BeginTime
表的行数少得多,并且EndTime
表在EndTime
列上有索引,这将比使用DateDiff(second, B.BeginTime, E.EndTime)
的任何内容。 现在它是sargable,这意味着有一个有效的“搜索参数”——因此当引擎扫描BeginTime
表时,它可以< em>查找到EndTime
表中。 需要仔细选择哪一列本身位于运算符的一侧 - 通过进行一些代数操作以切换到AND B.BeginTime >,将
BeginTime
单独放置,这可能是值得尝试的; E.EndTime - '00:00:10'DateDiff 的精度
我还应该指出
DateDiff
不会返回 elapsed时间,而是计算跨越的边界数量。 如果使用秒调用DateDiff
返回1
,这可能意味着3 毫秒
经过的时间,也可能意味着1997 毫秒
代码>! 这本质上是 +- 1 时间单位的精度。 为了获得 +- 1/2 时间单位的更好精度,您需要使用以下查询来比较0
与EndTime - BegTime
:现在最大舍入误差仅为 1第二个总数,而不是两个(实际上是一个 Floor() 操作)。 请注意,您只能减去
datetime
数据类型 - 要减去date
或time
值,您必须将其转换为datetime
或使用其他方法来获得更好的精度(大量DateAdd
、DateDiff
以及可能的其他垃圾,或者可能使用更高精度的时间单位和划分)。在计算小时、天或月等较大单位时,这一原则尤其重要。
1 个月
的DateDiff
可能相隔 62 天(想想 2013 年 7 月 1 日 - 2013 年 8 月 31 日)!Note: When I originally wrote this answer I said that an index on one of the columns could create a query that performs better than other answers (and mentioned Dan Fuller's). However, I was not thinking 100% correctly. The fact is, without a computed column or indexed (materialized) view, a full table scan is going to be required, because the two date columns being compared are from the same table!
I believe there is still value in the information below, namely 1) the possibility of improved performance in the right situation, as when the comparison is between columns from different tables, and 2) promoting the habit in SQL developers of following best practice and reshaping their thinking in the right direction.
Making Conditions Sargable
The best practice I'm referring to is one of moving one column to be alone on one side of the comparison operator, like so:
As I said, this will not avoid a scan on a single table, however, in a situation like this it could make a huge difference:
EndTime
is in both conditions now alone on one side of the comparison. Assuming that theBeginTime
table has many fewer rows, and theEndTime
table has an index on columnEndTime
, this will perform far, far better than anything usingDateDiff(second, B.BeginTime, E.EndTime)
. It is now sargable, which means there is a valid "search argument"--so as the engine scans theBeginTime
table, it can seek into theEndTime
table. Careful selection of which column is by itself on one side of the operator is required--it can be worth experimenting by puttingBeginTime
by itself by doing some algebra to switch toAND B.BeginTime > E.EndTime - '00:00:10'
Precision of DateDiff
I should also point out that
DateDiff
does not return elapsed time, but instead counts the number of boundaries crossed. If a call toDateDiff
using seconds returns1
, this could mean3 ms
elapsed time, or it could mean1997 ms
! This is essentially a precision of +- 1 time units. For the better precision of +- 1/2 time unit, you would want the following query comparing0
toEndTime - BegTime
:This now has a maximum rounding error of only one second total, not two (in effect, a floor() operation). Note that you can only subtract the
datetime
data type--to subtract adate
or atime
value you would have to convert todatetime
or use other methods to get the better precision (a whole lot ofDateAdd
,DateDiff
and possibly other junk, or perhaps using a higher precision time unit and dividing).This principle is especially important when counting larger units such as hours, days, or months. A
DateDiff
of1 month
could be 62 days apart (think July 1, 2013 - Aug 31 2013)!您无法在 where 语句中访问 select 语句中定义的列,因为它们只有在执行了 where 后才会生成。
但是,您可以执行此操作
作为旁注 - 这实际上将 DATEDIFF 根据其首次定义的位置移动到 where 语句中。 在 where 语句中的列上使用函数会导致索引无法有效使用,如果可能的话应该避免,但是如果您必须使用 datediff 那么您就必须这样做!
You can't access columns defined in the select statement in the where statement, because they're not generated until after the where has executed.
You can do this however
As a sidenote - this essentially moves the DATEDIFF into the where statement in terms of where it's first defined. Using functions on columns in where statements causes indexes to not be used as efficiently and should be avoided if possible, however if you've got to use datediff then you've got to do it!