请告诉我,如果我遗失了什么,如果我失去了理智
以下查询产生零错误
DECLARE @Test TABLE(
ID INT,
Val FLOAT
)
INSERT INTO @Test SELECT 1, 0
;WITH Grouped AS (
SELECT ID,
Val,
SUM(Val) OVER (PARTITION BY ID) TotalVal
FROM @Test
)
, Filtered AS (
SELECT *
FROM Grouped
WHERE TotalVal != 0
)
SELECT *
FROM Filtered
WHERE Val / TotalVal > 0.05
如下所示不会产生相同的错误
DECLARE @Test TABLE(
ID INT,
Val FLOAT
)
INSERT INTO @Test SELECT 1, 0
;WITH Grouped AS (
SELECT ID,
Val,
SUM(Val) OVER (PARTITION BY ID) TotalVal
FROM @Test
)
, Filtered AS (
SELECT *
FROM Grouped
WHERE TotalVal != 0
)
SELECT *,
Val / TotalVal Test
FROM Filtered
从查看估计的查询计划,第一个查询尝试将where子句优化为
[Val]/[Expr1004]>(5.000000000000000e-002) AND [Expr1004]<>(0.000000000000000e+000)
我可以看到TotalVal != 0
位于实际devide by TotalVal
之后。
这是一个已知问题吗?有没有办法(除了使用另一个临时表)绕过这个。我知道我可以使用
来做到这一点CASE WHEN TotalVal = 0 THEN 0 ELSE Val / TotalVal END
但这会破坏第二次CTE声明的目的。
答案 0 :(得分:1)
转到此connect item并投票。
就个人而言,我对SQL Server的工作方式感到满意,因为它允许某种程度的优化来预先计算(简化)一个表达式而不是将组件向前推进以便稍后计算(即使它有意义逻辑)。
至于你的查询,是的,Filtered CTE是一个非事件,应该进入最终查询。以这种方式编写表明您认为CTE以某种方式处理并且缓存在内存中。事实并非如此 - 请参阅另一个问题this answer。有关SQL Server CTE实现的扩展读取,请访问this article。