Where子句中的SQL Row_Number()函数

86 sql t-sql sql-server analytic-functions

Row_Number()在where子句中找到了一个用函数回答的问题.当我尝试一个查询时,我收到以下错误:

"消息4108,级别15,状态1,行1窗口函数只能出现在SELECT或ORDER BY子句中."

这是我试过的查询.如果有人知道如何解决这个问题,请告诉我.

SELECT employee_id 
FROM V_EMPLOYEE 
WHERE row_number() OVER ( ORDER BY employee_id ) > 0 
ORDER BY Employee_ID
Run Code Online (Sandbox Code Playgroud)

Sco*_*vey 85

要解决此问题,请将您的select语句包装在CTE中,然后您可以查询CTE并在where子句中使用窗口函数的结果.

WITH MyCte AS 
(
    select   employee_id,
             RowNum = row_number() OVER ( order by employee_id )
    from     V_EMPLOYEE 
    ORDER BY Employee_ID
)
SELECT  employee_id
FROM    MyCte
WHERE   RowNum > 0
Run Code Online (Sandbox Code Playgroud)

  • 我试图避免CTE.这是我正在寻找的更糟糕的情况.谢谢 (7认同)
  • 如果使用子查询而不是CTE,它可能会运行得更快.在某些情况下,我的性能提升了1.5倍 (3认同)
  • CTE SELECT中也应该有TOP,否则SQL 2008 Server将不会因为ORDER BY而执行查询(除非使用TOP,否则不支持) (3认同)
  • 我正在使用SQL2005(呃) - 我可以通过在FROM之后删除"ORDER BY"来避免使用"TOP".无论如何,OVER之后的(Order By)是多余的. (2认同)

Qua*_*noi 59

SELECT  employee_id
FROM    (
        SELECT  employee_id, ROW_NUMBER() OVER (ORDER BY employee_id) AS rn
        FROM    V_EMPLOYEE
        ) q
WHERE   rn > 0
ORDER BY
        Employee_ID
Run Code Online (Sandbox Code Playgroud)

请注意,此过滤器是多余的:ROW_NUMBER()1并且始终大于0.

  • @Quassnoi,可读性是良好编码的关键,翻译rn(或其他缩写别名)的认知努力为你自己和维护代码的人增加了.NB,微软首先命中,SELECT ROW_NUMBER()OVER(订购SalesYTD DESC)AS Row,...我之前也没有碰到过,所以你的"通用"里程可能会有所不同. (3认同)
  • @DavideChicco.it:在SQL Server中,派生表需要一个别名(我应该写'AS q`代替,但这也可以). (2认同)
  • 可读性是我在命名别名时的重点.您可以将rn编写为RowNumber,将q编写为DerivedTable,并将where子句写为DerivedTable.RowNumber> 0.在我看来,如果代码在您的脑海中并不新鲜,那么在6个月内这将更加容易混淆. (2认同)
  • @EdwardComeau:`rn`是这些天行号的普遍接受的首字母缩略词.尝试在google搜索字符串中键入"row_number over ..."并查看它的建议. (2认同)

小智 30

Select * from 
(
    Select ROW_NUMBER() OVER ( order by Id) as 'Row_Number', * 
    from tbl_Contact_Us
) as tbl
Where tbl.Row_Number = 5
Run Code Online (Sandbox Code Playgroud)


Mat*_*nes 19

我想你想要这样的东西:

SELECT employee_id 
FROM  (SELECT employee_id, row_number() 
       OVER (order by employee_id) AS 'rownumber' 
       FROM V_EMPLOYEE) TableExpressionsMustHaveAnAliasForDumbReasons
WHERE rownumber > 0
Run Code Online (Sandbox Code Playgroud)

  • 如果上述查询不适合您,请为表创建别名.将第二行修改为"From V_EMPLOYEE"A`,即将A添加为别名. (4认同)

Jam*_*all 8

我觉得所有显示使用 CTE 或子查询的答案都足以解决此问题,但我没有看到任何人深入了解 OP 出现问题的原因。OP建议不起作用的原因是由于此处的逻辑查询处理顺序:

  1. 加入
  2. 在哪里
  3. 通过...分组
  4. 带立方体/汇总
  5. 选择
  6. 清楚的
  7. 订购者
  8. 最佳
  9. 偏移/取回

我相信这对答案有很大的帮助,因为它解释了为什么会出现这样的问题。WHERE总是在SELECT使 CTE 或子查询成为许多功能所必需的之前处理。您将在 SQL Server 中看到很多。


Sha*_*nce 7

在回答关于rexem的答案的评论时,关于内联视图或CTE是否会更快,我重新构建查询以使用表I,并且每个人都可以使用:sys.objects.

WITH object_rows AS (
    SELECT object_id, 
        ROW_NUMBER() OVER ( ORDER BY object_id) RN
    FROM sys.objects)
SELECT object_id
FROM object_rows
WHERE RN > 1

SELECT object_id
FROM (SELECT object_id, 
        ROW_NUMBER() OVER ( ORDER BY object_id) RN
    FROM sys.objects) T
WHERE RN > 1
Run Code Online (Sandbox Code Playgroud)

生成的查询计划完全相同.我希望在所有情况下,查询优化器都会提出相同的计划,至少在内联视图中简单替换CTE,反之亦然.

当然,在您自己的系统上尝试自己的查询,看看是否存在差异.

此外,row_number()where子句是Stack Overflow上给出的答案中的常见错误.row_number()在处理select子句之前,Logicaly 不可用.人们忘记了这一点,当他们回答而没有测试答案时,答案有时是错误的.(我自己犯了罪.)

  • @Joseph,但是如果你看一下OP在链接问题中发布的另一个答案,你会发现他链接的代码版本与接受的答案中的代码版本不同.我不知道为什么他接受了答案,即使它不会像输入的那样运行.也许它在被接受之后的某个时候被编辑过,也许这足以让他继续前进,即使没有完全正确. (2认同)

小智 7

WITH MyCte AS 
(
    select 
       employee_id,
       RowNum = row_number() OVER (order by employee_id)
    from V_EMPLOYEE 
)
SELECT  employee_id
FROM    MyCte
WHERE   RowNum > 0
ORDER BY employee_id
Run Code Online (Sandbox Code Playgroud)