8

我是使用分析函数的新手。

部门雇员工资
---- ----- ------
  100000 年 3 月 10 日
  10 约翰 200000
  10 斯科特 300000
  20 鲍勃 100000
  20 贝蒂 200000
  30艾伦100000
  30 汤姆 200000
  30 杰夫 300000

我想要最低工资的部门和员工。

结果应如下所示:

部门雇员工资
---- ----- ------
  100000 年 3 月 10 日
  20 鲍勃 100000
  30艾伦100000

编辑:这是我拥有的 SQL(但当然,它不工作,因为它也需要 group by 子句中的人员):

选择部门,
  雇员,
  MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY Salary)
来自我的表
按部门分组
4

4 回答 4

10

我认为 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() 的第二个原因是它只是回答了错误的问题。问题不是“在每个部门的薪水升序时,哪些记录的薪水排名第一”,而是“哪些记录的每个部门的薪水最低”。至少,这对我来说有很大的不同。

于 2009-10-08T07:06:55.840 回答
5

我认为您与原始查询非常接近。以下将运行并匹配您的测试用例:

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() 解决方案将返回两个员工——该部门不止一行。此答案将任意选择一个,并确保该部门只有一个。

于 2009-10-09T06:30:13.930 回答
3

您可以使用RANK()语法。例如,此查询将告诉您员工在其部门内的薪水大小排名:

SELECT
  dept,
  emp,
  salary,
  (RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
FROM EMPLOYEES

然后您可以从这里查询 where 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
于 2009-10-07T18:09:31.657 回答
-1
select e2.dept, e2.emp, e2.salary
from employee e2
where e2.salary = (select min(e1.salary) from employee e1)
于 2009-10-07T18:10:46.533 回答