【发布时间】:2015-09-04 22:22:47
【问题描述】:
当与 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
查询
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;
结果
+-------+-------------+-------------+-----------+
| KeyID | MatchValue1 | MatchValue2 | MatchTest |
+-------+-------------+-------------+-----------+
| 12 | 350000.00 | NULL | NULL |
+-------+-------------+-------------+-----------+
使用Cross Apply 不会按预期返回任何行。删除 CTE 并使用内联常量也不会返回任何行。
--Scalars, no row here...
SELECT LP.*
FROM dbo.TVFTest
(
12,
$350000,
350000
) LP;
【问题讨论】:
-
我相信这是因为您的 TVF
WHERE MatchValue1 != MatchValue2中有一个过滤器,并且您的每个测试都提供了匹配的值。所以它不返回任何匹配项。删除该条件,我认为您将获得预期的结果。 ... nvr mind,可能误解了您的问题... -
OUTER APPLY 的行为应该类似于针对函数的外部连接。我选择这个例子返回 0 个结果。但是,TVF 返回的所有列都应该为 NULL。第一个不是。我的问题是——为什么?我的代码中有错误还是其他原因?
-
很高兴你抓住了它。这个问题有点微妙。
-
您想看到更奇怪的东西,将值转换为金钱,您可以取回除 case 语句之外的每一行:
SELECT T.PropertyID, LP.KeyID, LP.MatchValue1, LP.MatchValue2, LP.MatchTest FROM (SELECT 12 AS PropertyID, cast(350000 as money) AS Ap1, cast(350000 as money) AS Ap2) T OUTER APPLY dbo.TVFTest(T.PropertyID, T.Ap1, T.Ap2) LP; -
也发生在 SQL Server 2014 上。这是一个错误。您可以通过connect.microsoft.com/SQLServer 举报
标签: sql-server sql-server-2008 tsql sql-server-2012