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

时间:2015-07-09 11:24:25

标签: sql-server sql-server-2008 tsql 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;

输出:

name    rn  crn
a   1   1
a   2   1
a   3   1
a   4   1
b   1   1
b   2   1
c   1   1

2 个答案:

答案 0 :(得分:4)

CROSS APPLY中的查询应用于#tmp中的每一行。查询选择它应用的那一行,即那一行的行号,当然是一行。

微软Technet上的this article可能会让您更深入地了解CROSS APPLY的工作原理。摘录突出了我在前一段中所写的内容:

  

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

答案 1 :(得分:3)

请注意,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

返回:

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