sql - SELECT 子句中的计算可以在应用 WHERE 谓词之前执行吗?

标签 sql sql-server

是否可以在应用 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 谓词的每个值上成功,我仍然会看到溢出发生。在每种失败情况下,源数据中始终存在一些零值。

我的猜测是,查询规划器有时决定在应用过滤器之前进行计算,因此允许使用零值,从而导致溢出。我无法确认这一点,因为溢出发生时我看不到执行计划。

我的理论可靠吗?有办法确认吗?我对证实这个理论更感兴趣。如果我的理论是正确的,那么我就知道如何解决问题。

最佳答案

唉,您无法控制过滤何时发生。 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 语句保证评估 then 之前的 when 子句,尽管在上下文中使用它时有一些特殊性聚合的。

关于sql - SELECT 子句中的计算可以在应用 WHERE 谓词之前执行吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22046828/

相关文章:

mysql - 为同一个表编写子查询来访问不同的记录

php - FluentPDO 似乎无法找到执行 OR 子句的方法

MySQL - 替换列值

sql-server - 去年相同日期的 SQL 语法

SQL 查询 - 从特定行过滤值到结果

sql-server - SQL Server 未使用,但已分配表空间

c# - 为什么我计算行数的原始查询总是返回 -1?

SQL 执行计划显示相同输入的不同结果

sql - IF THEN 在存储过程中循环

sql - 添加列是否删除数据