使用 ROW_NUMBER() 窗口函数选择行

Posted

技术标签:

【中文标题】使用 ROW_NUMBER() 窗口函数选择行【英文标题】:Selecting row with ROW_NUMBER() window function 【发布时间】:2019-12-04 22:11:32 【问题描述】:

我目前正在为我的工作流程编写查询。我试图通过应用 ROW_NUMBER() 函数来获取特定行,然后根据行位置选择行。但是,我收到以下 错误

SQL 编译错误:窗口函数 [ROW_NUMBER() OVER (ORDER BY EMPLOYEE.SALARY_GRADE_ID ASC NULLS LAST)] 出现在 SELECT、QUALIFY 和 ORDER BY 子句之外。

查询:

SELECT Employee.Salary_Grade_Id, SUM(Salary_Grades.Grade_Amount) AS total, ROW_NUMBER() OVER(ORDER 
BY Employee.Salary_Grade_Id) AS rowCol FROM Employee, Salary_Grades 
WHERE (Employee.Salary_Grade_Id = Salary_Grades.Grade_Id AND rowCol = 1) GROUP BY 
Employee.Salary_Grade_Id;

没有意义的是,当我删除AND rowCol = 1 时,查询工作没有错误。但是有了它,我得到了错误。这是怎么回事?

【问题讨论】:

学习使用正确、明确、标准 JOIN 语法。 【参考方案1】:

您的问题是 rowCol 是窗口函数 (ROW_NUMBER()) 的别名,它们不能出现在 WHERE 子句中。您可以改用QUALIFY 子句:

SELECT Employee.Salary_Grade_Id, 
       SUM(Salary_Grades.Grade_Amount) AS total, 
       ROW_NUMBER() OVER(ORDER BY Employee.Salary_Grade_Id) AS rowCol 
FROM Employee, Salary_Grades 
WHERE (Employee.Salary_Grade_Id = Salary_Grades.Grade_Id)
GROUP BY Employee.Salary_Grade_Id
QUALIFY rowCol = 1

请注意,您应该使用显式 JOIN 语法并将查询重写为

SELECT Employee.Salary_Grade_Id, 
       SUM(Salary_Grades.Grade_Amount) AS total, 
       ROW_NUMBER() OVER(ORDER BY Employee.Salary_Grade_Id) AS rowCol 
FROM Employee
JOIN Salary_Grades ON Employee.Salary_Grade_Id = Salary_Grades.Grade_Id
GROUP BY Employee.Salary_Grade_Id
QUALIFY rowCol = 1

【讨论】:

哦,QUALIFY 是对 SQL 的一个很好的扩展。 @LiamClarke 是的!它使编写这种查询很多更容易。 天哪!这个不错。我不知道这个方便的花絮。谢谢!我通常使用写出的内容。【参考方案2】:

WHERE 子句在开窗之前应用,因此您不能在 WHERE 子句中引用开窗函数。您需要使用子查询:

SELECT 
    grade_id, 
    sum(grade_amount) as total
FROM (
    SELECT
        Employee.Salary_Grade_Id as grade_id, 
        Salary_Grades.Grade_Amount AS grade_amount, 
        ROW_NUMBER() OVER(ORDER BY Employee.Salary_Grade_Id) AS rowCol 
    FROM Employee JOIN Salary_Grades ON Employee.Salary_Grade_Id = Salary_Grades.Grade_Id) x
WHERE  rowCol = 1
GROUP BY grade_id;

我还将您的连接谓词移到 FROM 子句中,作为一种最佳做法,以避免在谓词 Employee.Salary_Grade_Id = Salary_Grades.Grade_Id 被错误地删除时发生意外的笛卡尔连接。

【讨论】:

这是标准 SQL 的方式。 谢谢利亚姆。如果我没记错的话,您在这里使用的是作为派生表的子查询?

以上是关于使用 ROW_NUMBER() 窗口函数选择行的主要内容,如果未能解决你的问题,请参考以下文章

为啥将 ROW_NUMBER 定义为窗口函数?

窗口函数 ROW_NUMBER

开窗函数和row_number()

如何选择另一个选择查询结果的第 10、20、30 ... 行

Hive row_number() 中的自定义排序,按窗口函数排序

PostgreSQL 高级SQL(五) 内建窗口函数