使用普通 SQL 从结果集中获取第 n个最高值的最简单方法是什么?
结果集会很大,因此也需要考虑性能。
这篇文章深入讨论了这个问题,我将在下面引用它的代码:
解决方案 1:这个找到第 N 高薪的 SQL 应该适用于 SQL Server、MySQL、DB2、Oracle、Teradata 和几乎任何其他 RDBMS:(注意:由于子查询导致性能低下)
SELECT * /*This is the outer query part */
FROM Employee Emp1
WHERE (N-1) = ( /* Subquery starts here */
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary)
在上面的查询中要理解的最重要的事情是,每次外部查询处理一行时都会评估子查询。换句话说,内部查询不能独立于外部查询来处理,因为内部查询也使用 Emp1 值。
为了找到第 N 个最高的薪水,我们只需要找到恰好比自己大 N-1 的薪水。
解决方案二:在 SQL Server 中使用 TOP 关键字查找第 n 高的薪水
SELECT TOP 1 Salary
FROM (
SELECT DISTINCT TOP N Salary
FROM Employee
ORDER BY Salary DESC
) AS Emp
ORDER BY Salary
解决方案3:在不使用TOP的情况下,在SQL Server中查找第n个最高薪水
SELECT Salary FROM Employee
ORDER BY Salary DESC OFFSET N-1 ROW(S)
FETCH FIRST ROW ONLY
请注意,我没有亲自测试过上面的 SQL,我相信它只会在 SQL Server 2012 及更高版本中工作。
解决方案 4:在 MySQL 中工作
SELECT Salary FROM Employee
ORDER BY Salary DESC LIMIT n-1,1
LIMIT 子句在该查询中接受两个参数——第一个参数指定要返回的第一行的偏移量,第二个参数指定要返回的最大行数。
解决方案 5:在 Oracle 中工作
select * from (
select Emp.*,
row_number() over (order by Salary DESC) rownumb
from Employee Emp
)
where rownumb = n; /*n is nth highest salary*/
解决方案 6:以 Oracle 方式工作 2
select * FROM (
select EmployeeID, Salary
,rank() over (order by Salary DESC) ranking
from Employee
)
WHERE ranking = N;
这是 T-SQL(SQL-Server 2005 及更高版本)方法,使用ROW_NUMBER
:
WITH CTE AS
(
SELECT
Col1, Col2, ValueCol,
RN = ROW_NUMBER() OVER (ORDER BY ValueCol DESC) -- change to ASC if you want lowest first
FROM
dbo.TableName
)
SELECT
Col1, Col2, ValueCol
FROM
CTE
WHERE
RN = @nthhighestvalue
如果您希望所有行具有相同的值,请DENSE RANK
改用。
首先生成一个有序的编号数据集,然后从中进行选择。精确的语法取决于 RDBMS,但是,例如,在 Oracle 中,您可以这样做
SELECT ROWNUM, SOMEVAL
FROM (SELECT SOMEVAL FROM SOMETABLE ORDER BY SOMEVAL DESC)
鉴于上述设置,您可以
SELECT SOMEVAL WHERE ROWNUM = :N
在甲骨文中:
SELECT * FROM (
SELECT col1, ROW_NUMBER()OVER(ORDER BY col1) rnum_col1 FROM table1
) WHERE rnum_col1 = 10;
假设你想找到第 5 高的薪水,你首先按降序排列前 5 个不同的薪水顺序,这样最后一个就是第 5 高的薪水(参见内部查询)。然后,您按升序重新排序并取第一个。
SELECT TOP 1 Salary FROM
(
SELECT DISTINCT TOP 5 Salary
FROM Employee
ORDER BY Salary DESC) t
ORDER BY Salary ASC
在一般数据库中,您可以使用一个子查询和两个order by
s. 问题是 top/limit/rownum 语法不是标准的。在某些数据库中,您会编写:
子查询将列出前“n”个最高工资值。从该列表中,最小值将是第 n 个最高薪水。
`SELECT min(salary) FROM
(SELECT DISTINCT TOP n salary FROM EmployeeTable ORDER BY salary desc);`
例如:- SQL 查询以查找第三个最高薪水
`SELECT min(salary) FROM
(SELECT DISTINCT TOP 3 salary FROM EmployeeTable ORDER BY salary desc);`
您必须承担排序的开销,在我的示例rownum
中是排序的行号,而不是物理位置。
因为每个人都在使用分析函数来展示它是如何工作的,所以这里是一个:
select foo,bar, max(baz)
from
(
select *
from
(
select foo,bar,baz, row_number() over
(partition by some_identifier_that_Groups order by value DESC) rn
)
where rn = 1 -- get the highest value for each partition
) group by foo,bar