为什么 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 子句。所以它将 nameid 视为文字。为了说明,对于 #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