我刚开始使用分析功能。
DEPT EMP SALARY ---- ----- ------ 10 MARY 100000 10 JOHN 200000 10 SCOTT 300000 20 BOB 100000 20 BETTY 200000 30 ALAN 100000 30 TOM 200000 30 JEFF 300000
我希望部门和员工的工资最低。
结果应该如下:
DEPT EMP SALARY ---- ----- ------ 10 MARY 100000 20 BOB 100000 30 ALAN 100000
编辑:这是我的SQL(当然,它不起作用,因为它也需要group by子句中的人员):
SELECT dept, emp, MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary) FROM mytable GROUP BY dept
答案 0 :(得分:9)
我认为Rank()函数不是这样的,有两个原因。
首先,它可能比基于Min()的方法效率低。
原因是查询必须在扫描数据时维护每个部门所有工资的有序列表,然后通过重新读取此列表来分配等级。显然,如果没有可用于此的索引,则在读取最后一个数据项之前无法分配排名,并且列表的维护费用很高。
因此,Rank()函数的性能取决于要扫描的元素总数,如果数量足以使排序溢出到磁盘,则性能将崩溃。
这可能更有效:
select dept,
emp,
salary
from
(
SELECT dept,
emp,
salary,
Min(salary) Over (Partition By dept) min_salary
FROM mytable
)
where salary = min_salary
/
此方法仅要求查询为每个部门维护目前为止遇到的最小值的单个值。如果遇到新的最小值,则修改现有值,否则将丢弃新值。必须在内存中保留的元素总数与部门数量有关,而不是扫描的行数。
可能是Oracle有一个代码路径来识别在这种情况下确实不需要计算Rank,但我不打赌它。
不喜欢Rank()的第二个原因是它只是回答了错误的问题。问题不在于“当每个部门的工资按升序排序时,哪些记录的工资是第一个排名”,它是“哪个记录的工资是每个部门的最低工资”。至少对我来说这是一个很大的不同。
答案 1 :(得分:4)
我认为你与原始查询非常接近。以下内容将运行并与您的测试用例匹配:
SELECT dept,
MIN(emp) KEEP(DENSE_RANK FIRST ORDER BY salary, ROWID) AS emp,
MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary, ROWID) AS salary
FROM mytable
GROUP BY dept
与RANK()解决方案相比,这个解决方案保证每个部门最多一行。但这暗示了一个问题:在最低工资有两名员工的部门会发生什么? RANK()解决方案将返回两个员工 - 该部门不止一行。这个答案将任意挑选一个,并确保该部门只有一个。
答案 2 :(得分:3)
您可以使用RANK()
语法。例如,此查询将告诉您员工在其部门中的工资在多大程度上的排名:
SELECT
dept,
emp,
salary,
(RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
FROM EMPLOYEES
然后,您可以从salary_rank_within_dept = 1
:
SELECT * FROM
(
SELECT
dept,
emp,
salary,
(RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
FROM EMPLOYEES
)
WHERE salary_rank_within_dept = 1
答案 3 :(得分:-1)
select e2.dept, e2.emp, e2.salary
from employee e2
where e2.salary = (select min(e1.salary) from employee e1)