为什么窗口功能在CROSS APPLY中不起作用?

Dmi*_*sev 3 t-sql sql-server sql-server-2008 sql-server-2008-r2 cross-apply

有一个简单的代码。我一直以为ROW_NUMBER外部和CROSS APPLY子句中的那个都应该生成相同的输出(在我的示例中,我例外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;
Run Code Online (Sandbox Code Playgroud)

输出:

name    rn  crn
a   1   1
a   2   1
a   3   1
a   4   1
b   1   1
b   2   1
c   1   1
Run Code Online (Sandbox Code Playgroud)

TT.*_*TT. 5

CROSS APPLY中的查询将应用于中的每一行#tmp。该查询为要应用到的那一行选择该行的行号,该行号当然是第一行。

也许Microsoft Technet上的这篇文章可以使您对CROSS APPLY的工作方式有更深入的了解。摘录突出了我在上一段中写的内容:

APPLY运算符允许您为查询的外部表表达式返回的每一行调用表值函数。表值函数充当右输入,而外部表表达式充当左输入。从左输入开始为每一行评估右输入,并将产生的行合并为最终输出。APPLY运算符产生的列列表是左输入中的列集,其后是右输入返回的列列表。


Fel*_*tan 5

请注意,APPLY使用主查询中的字段作为参数

SELECT  ROW_NUMBER() OVER ( PARTITION BY name ORDER BY id ) AS crn
Run Code Online (Sandbox Code Playgroud)

上述查询没有子句FROM。所以它将nameand视为id文字。为了说明这一点,对于 的第一行#tmp,结果查询是CROSS APPLY

SELECT  ROW_NUMBER() OVER ( PARTITION BY (SELECT 'a') ORDER BY (SELECT 1)) AS crn
Run Code Online (Sandbox Code Playgroud)

返回:

crn
--------------------
1
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)