CDC*_*CDC 14 t-sql sql-server sql-server-2008 sql-server-2012
当与OUTER APPLY一起使用时,我在表值函数上遇到了一些奇怪的行为.我有一个简单的内联函数,它返回一些基于另一个表中的行的简单计算.当TVF的输入值是硬编码标量时,不返回任何行.当我在CTE中使用相同的标量并从中生成一行时,然后使用CROSS APPLY将它们作为列提供,没有结果集.当我使用OUTER APPLY执行相同操作时,我得到1行(如预期的那样),但是其中两个是输出列NULL
,另外两个是NOT NULL
.基于BOL,这不应该发生OUTER APPLY
.这是用户错误吗?我写了一个简单的版本来演示这个问题.
--Test set-up
CREATE FUNCTION dbo.TVFTest
(
@keyID INT,
@matchValue1 MONEY,
@matchValue2 MONEY
)
RETURNS TABLE AS RETURN
(
WITH TestRow
AS (SELECT @keyID AS KeyID,
@matchValue1 AS MatchValue1,
@matchValue2 AS MatchValue2)
SELECT KeyID,
MatchValue1,
MatchValue2,
CASE
WHEN MatchValue1 <> MatchValue2
THEN 'Not equal'
ELSE 'Something else'
END AS MatchTest
FROM TestRow
WHERE MatchValue1 <> MatchValue2
)
GO
Run Code Online (Sandbox Code Playgroud)
询问
WITH Test AS
(
SELECT 12 AS PropertyID,
$350000 AS Ap1,
350000 AS Ap2
)
SELECT LP.*
FROM Test T
OUTER APPLY dbo.TVFTest
(
T.PropertyID,
T.Ap1,
T.Ap2
) LP;
Run Code Online (Sandbox Code Playgroud)
结果
+-------+-------------+-------------+-----------+
| KeyID | MatchValue1 | MatchValue2 | MatchTest |
+-------+-------------+-------------+-----------+
| 12 | 350000.00 | NULL | NULL |
+-------+-------------+-------------+-----------+
Run Code Online (Sandbox Code Playgroud)
使用Cross Apply
返回没有按预期方式行.同时删除CTE并使用内联常量不会返回任何行.
--Scalars, no row here...
SELECT LP.*
FROM dbo.TVFTest
(
12,
$350000,
350000
) LP;
Run Code Online (Sandbox Code Playgroud)
Mar*_*ith 14
这肯定是产品中的一个错误.
已报告类似的错误,并将其关闭为"无法修复".
包括这个问题,链接的连接项和本网站上的另外 两个问题我已经看到了四种内联TVF的此类行为案例OUTER APPLY
- 所有这些都是格式化的
OUTER APPLY dbo.SomeFunction(...) F
Run Code Online (Sandbox Code Playgroud)
写作时返回正确的结果
OUTER APPLY (SELECT * FROM dbo.SomeFunction(...)) F
Run Code Online (Sandbox Code Playgroud)
所以这看起来像是一种可能的解决方法.
对于查询
WITH Test AS
(
SELECT 12 AS PropertyID,
$350000 AS Ap1,
350000 AS Ap2
)
SELECT LP.*
FROM Test T
OUTER APPLY dbo.TVFTest
(
T.PropertyID,
T.Ap1,
T.Ap2
) LP;
Run Code Online (Sandbox Code Playgroud)
执行计划看起来像
并且最终投影中的输出列列表是.Expr1000,Expr1001,Expr1003,Expr1004.
但是,在右下角的常量表中只定义了其中两列.
文字$350000
在右上角的常量表(Expr1001)中定义.然后将其外部连接到右下角的常量表中.由于没有行匹配连接条件,因此在那里定义的两列(Expr1003,Expr1004)被正确评估为NULL.然后最终计算标量将文字12
作为新列(Expr1000)添加到数据流中,而不考虑外连接的结果.
这些都不是正确的语义.与内联TVF手动内联时的(正确)计划进行比较.
WITH Test
AS (SELECT 12 AS PropertyID,
$350000 AS Ap1,
350000 AS Ap2)
SELECT LP.*
FROM Test T
OUTER APPLY (SELECT KeyID,
MatchValue1,
MatchValue2,
CASE
WHEN MatchValue1 <> MatchValue2
THEN 'Not equal'
ELSE 'Something else'
END AS MatchTest
FROM (SELECT T.PropertyID AS KeyID,
T.Ap1 AS MatchValue1,
T.Ap2 AS MatchValue2) TestRow
WHERE MatchValue1 <> MatchValue2) LP
Run Code Online (Sandbox Code Playgroud)
这里是最终投影中使用的列Expr1003, Expr1004, Expr1005, Expr1006
.所有这些都在右下角的恒定扫描中定义.
在TVF的情况下,这一切似乎很早就出错了.
添加OPTION (RECOMPILE, QUERYTRACEON 3604, QUERYTRACEON 8606);
显示进程的输入树已经不正确.在SQL中表达它是类似的.
SELECT Expr1000,
Expr1001,
Expr1003,
Expr1004
FROM (VALUES (12,
$350000,
350000)) V1(Expr1000, Expr1001, Expr1002)
OUTER APPLY (SELECT Expr1003,
IIF(Expr1001 <> Expr1003,
'Not equal',
'Something else') AS Expr1004
FROM (SELECT CAST(Expr1002 AS MONEY) AS Expr1003) D
WHERE Expr1001 <> Expr1003) OA
Run Code Online (Sandbox Code Playgroud)
该跟踪标志的完整输出如下(并且8605显示基本相同的树.)
*** Input Tree: ***
LogOp_Project COL: Expr1000 COL: Expr1001 COL: Expr1003 COL: Expr1004
LogOp_Apply (x_jtLeftOuter)
LogOp_Project
LogOp_ConstTableGet (1) [empty]
AncOp_PrjList
AncOp_PrjEl COL: Expr1000
ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=12)
AncOp_PrjEl COL: Expr1001
ScaOp_Const TI(money,ML=8) XVAR(money,Not Owned,Value=(10000units)=(-794967296))
AncOp_PrjEl COL: Expr1002
ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=350000)
LogOp_Project
LogOp_Select
LogOp_Project
LogOp_ConstTableGet (1) [empty]
AncOp_PrjList
AncOp_PrjEl COL: Expr1003
ScaOp_Convert money,Null,ML=8
ScaOp_Identifier COL: Expr1002
ScaOp_Comp x_cmpNe
ScaOp_Identifier COL: Expr1001
ScaOp_Identifier COL: Expr1003
AncOp_PrjList
AncOp_PrjEl COL: Expr1004
ScaOp_IIF varchar collate 53256,Var,Trim,ML=14
ScaOp_Comp x_cmpNe
ScaOp_Identifier COL: Expr1001
ScaOp_Identifier COL: Expr1003
ScaOp_Const TI(varchar collate 53256,Var,Trim,ML=9) XVAR(varchar,Owned,Value=Len,Data = (9,Not equal))
ScaOp_Const TI(varchar collate 53256,Var,Trim,ML=14) XVAR(varchar,Owned,Value=Len,Data = (14,Something else))
AncOp_PrjList
*******************
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
896 次 |
最近记录: |