在应用WHERE子句之前,是否可以在SQL查询的SELECT子句中执行计算?我的目标是SQL Server 2008 R2,但我对一般感兴趣。我认为这是SQL标准所涵盖的。
采取下表并查询:
CREATE TABLE TestTable
(
ID bigint primary key,
Accessed bigint null,
Created bigint null,
Modified bigint null
)
--insert the data here
SELECT ID, dateadd(ms, (Created % 864000000000) / 10000, dateadd(day, (Created / 864000000000) - 55517, '17530101')) AS EventTime, 3 AS EventType
FROM TestTable
WHERE (Created IS NOT NULL)
AND (Created <> 0)
AND (Created <= 2650467743999999999)
WHERE谓词旨在过滤掉在SELECT子句中通过嵌套的dateadd()调用时会导致日期时间溢出的值。在某些情况下,我仍然看到溢出发生,即使我确信计算将在满足WHERE谓词的每个值上成功。在每种情况下都会出现故障,源数据中总会有一些零值。
我的猜测是查询规划器有时会在应用过滤器之前决定进行计算,从而允许零值导致溢出。我无法确认,因为在溢出发生时我看不到执行计划。
我的理论听起来不错?有没有办法确认呢?我更感兴趣的是确认理论而不是其他任何东西。如果我的理论是正确的,那么我知道如何解决这个问题。
答案 0 :(得分:3)
唉,你无法控制何时发生过滤。 SQL Server认为通过在实际执行计划中的SELECT
过滤之前移动WHERE
计算来帮助您。您不需要这样的优点,因为它会导致错误。
有一个修复,即使用case
语句:
SELECT ID,
(case when Created <> 0 and Created < 2650467743999999999
then dateadd(ms, (Created % 864000000000) / 10000, dateadd(day, (Created / 864000000000) - 55517, '17530101'))
end) AS EventTime, 3 AS EventType
FROM TestTable
WHERE (Created IS NOT NULL) AND (Created <> 0) AND (Created <= 2650467743999999999);
如果您不喜欢重复条件,可以将其放在子查询中并测试NULL
:
SELECT *
FROM (SELECT ID,
(case when Created <> 0 and Created < 2650467743999999999
then dateadd(ms, (Created % 864000000000) / 10000, dateadd(day, (Created / 864000000000) - 55517, '17530101'))
end) AS EventTime, 3 AS EventType
FROM TestTable
) tt
WHERE EventTime is not null;
case
语句保证在when
之前评估then
子句,尽管在聚合的上下文中使用它时有一些特殊性。