为什么 window 函数在 CROSS APPLY 中不起作用?
Why does window functions not work in CROSS APPLY?
有一个简单的代码。我一直认为 ROW_NUMBER 之外的和 CROSS APPLY 子句中的那个都应该生成相同的输出(在我的例子中我 excepct rn = crn)。你能解释一下为什么不是那样吗?
CREATE TABLE #tmp ( id INT, name VARCHAR(200) );
INSERT INTO #tmp
VALUES ( 1, 'a' ),
( 2, 'a' ),
( 3, 'a' ),
( 4, 'b' ),
( 5, 'b' ),
( 6, 'c' ),
( 7, 'a' );
SELECT name,
ROW_NUMBER() OVER ( PARTITION BY name ORDER BY id ) AS rn,
a.crn
FROM #tmp
CROSS APPLY (
SELECT ROW_NUMBER() OVER ( PARTITION BY name ORDER BY id ) AS crn
) a;
输出:
name rn crn
a 1 1
a 2 1
a 3 1
a 4 1
b 1 1
b 2 1
c 1 1
CROSS APPLY 中的查询应用于 #tmp
中的每一行。查询选择它所应用的那一行,那一行的行号当然是一。
也许 Microsoft 的 Technet 上的 this article 可以让您更深入地了解 CROSS APPLY 的工作原理。突出显示我在上一段中所写内容的摘录:
The APPLY operator allows you to invoke a table-valued function for each row returned by an outer table expression of a query. The table-valued function acts as the right input and the outer table expression acts as the left input. The right input is evaluated for each row from the left input and the rows produced are combined for the final output. The list of columns produced by the APPLY operator is the set of columns in the left input followed by the list of columns returned by the right input.
请注意,APPLY
正在使用您主查询中的字段作为 参数。
SELECT ROW_NUMBER() OVER ( PARTITION BY name ORDER BY id ) AS crn
上述查询没有 FROM
子句。所以它将 name
和 id
视为文字。为了说明,对于 #tmp
的第一行,CROSS APPLY
的结果查询是:
SELECT ROW_NUMBER() OVER ( PARTITION BY (SELECT 'a') ORDER BY (SELECT 1)) AS crn
哪个returns:
crn
--------------------
1
这是您对每一行 CROSS APPLY
的结果。
达到预期效果:
SELECT
t.name,
ROW_NUMBER() OVER ( PARTITION BY t.name ORDER BY t.id ) AS rn,
a.crn
FROM #tmp t
CROSS APPLY(
SELECT id, ROW_NUMBER() OVER (PARTITION BY name ORDER BY id ) AS crn
FROM #tmp
) a
WHERE t.id = a.id
有一个简单的代码。我一直认为 ROW_NUMBER 之外的和 CROSS APPLY 子句中的那个都应该生成相同的输出(在我的例子中我 excepct rn = crn)。你能解释一下为什么不是那样吗?
CREATE TABLE #tmp ( id INT, name VARCHAR(200) );
INSERT INTO #tmp
VALUES ( 1, 'a' ),
( 2, 'a' ),
( 3, 'a' ),
( 4, 'b' ),
( 5, 'b' ),
( 6, 'c' ),
( 7, 'a' );
SELECT name,
ROW_NUMBER() OVER ( PARTITION BY name ORDER BY id ) AS rn,
a.crn
FROM #tmp
CROSS APPLY (
SELECT ROW_NUMBER() OVER ( PARTITION BY name ORDER BY id ) AS crn
) a;
输出:
name rn crn
a 1 1
a 2 1
a 3 1
a 4 1
b 1 1
b 2 1
c 1 1
CROSS APPLY 中的查询应用于 #tmp
中的每一行。查询选择它所应用的那一行,那一行的行号当然是一。
也许 Microsoft 的 Technet 上的 this article 可以让您更深入地了解 CROSS APPLY 的工作原理。突出显示我在上一段中所写内容的摘录:
The APPLY operator allows you to invoke a table-valued function for each row returned by an outer table expression of a query. The table-valued function acts as the right input and the outer table expression acts as the left input. The right input is evaluated for each row from the left input and the rows produced are combined for the final output. The list of columns produced by the APPLY operator is the set of columns in the left input followed by the list of columns returned by the right input.
请注意,APPLY
正在使用您主查询中的字段作为 参数。
SELECT ROW_NUMBER() OVER ( PARTITION BY name ORDER BY id ) AS crn
上述查询没有 FROM
子句。所以它将 name
和 id
视为文字。为了说明,对于 #tmp
的第一行,CROSS APPLY
的结果查询是:
SELECT ROW_NUMBER() OVER ( PARTITION BY (SELECT 'a') ORDER BY (SELECT 1)) AS crn
哪个returns:
crn
--------------------
1
这是您对每一行 CROSS APPLY
的结果。
达到预期效果:
SELECT
t.name,
ROW_NUMBER() OVER ( PARTITION BY t.name ORDER BY t.id ) AS rn,
a.crn
FROM #tmp t
CROSS APPLY(
SELECT id, ROW_NUMBER() OVER (PARTITION BY name ORDER BY id ) AS crn
FROM #tmp
) a
WHERE t.id = a.id