SQL:聚合函数和分组依据

时间:2008-09-09 01:49:32

标签: sql oracle aggregate

考虑Oracle emp表。我希望通过department = 20job = clerk让员工获得最高薪水。还假设没有“empno”列,并且主键涉及多个列。你可以这样做:

select * from scott.emp
where deptno = 20 and job = 'CLERK'
and sal =  (select max(sal) from scott.emp
            where deptno = 20 and job = 'CLERK')

这有效,但我必须复制测试deptno = 20和job ='CLERK',我想避免。有没有更优雅的方式来写这个,可能使用group by?顺便说一句,如果这很重要,我正在使用Oracle。

6 个答案:

答案 0 :(得分:3)

以下略有过度设计,但对于“top x”查询来说是一个很好的SQL模式。

SELECT 
 * 
FROM 
 scott.emp
WHERE 
 (deptno,job,sal) IN
 (SELECT 
   deptno,
   job,
   max(sal) 
  FROM 
   scott.emp
  WHERE 
   deptno = 20 
   and job = 'CLERK'
  GROUP BY 
   deptno,
   job
  )

另请注意,这将适用于Oracle和Postgress(我认为),但不适用于MS SQL。对于MS SQL中的类似内容,请参阅问题SQL Query to get latest price

答案 1 :(得分:2)

如果我确定目标数据库,我会选择Mark Nold的解决方案,但如果您想要一些与方言无关的SQL *,请尝试

SELECT * 
FROM scott.emp e
WHERE e.deptno = 20 
AND e.job = 'CLERK'
AND e.sal = (
  SELECT MAX(e2.sal) 
  FROM scott.emp e2
  WHERE e.deptno = e2.deptno 
  AND e.job = e2.job
)

*我相信这应该适用于所有地方,但我没有环境来测试它。

答案 2 :(得分:1)

在Oracle中,我使用分析函数来完成它,所以你只需要查询一次emp表:

SELECT *
  FROM (SELECT e.*, MAX (sal) OVER () AS max_sal
          FROM scott.emp e
         WHERE deptno = 20 
           AND job = 'CLERK')
 WHERE sal = max_sal

它更简单,更易读,更高效。

如果要将其修改为列表列出所有部门的此信息,那么您需要在OVER中使用“PARTITION BY”子句:

SELECT *
  FROM (SELECT e.*, MAX (sal) OVER (PARTITION BY deptno) AS max_sal
          FROM scott.emp e
         WHERE job = 'CLERK')
 WHERE sal = max_sal
ORDER BY deptno

答案 3 :(得分:0)

太棒了!我不知道你可以将(x,y,z)与SELECT语句的结果进行比较。这适用于Oracle。

作为其他读者的旁注,上述查询在“(deptno,job,sal)”之后缺少“=”。也许Stack Overflow格式化器吃了它(?)。

再次感谢Mark。

答案 4 :(得分:0)

在Oracle中,您还可以使用EXISTS语句,在某些情况下更快。

例如...... SELECT名称,编号 来自cust 在哪里cust IN   (SELECT cust_id FROM big_table)  AND输入> SYSDATE -1 会很慢。

但 SELECT名称,编号 来自cust c 在哪里存在   (SELECT cust_id FROM big_table WHERE cust_id = c.cust_id )  AND输入> SYSDATE -1 通过适当的索引可以非常快。您也可以将它与多个参数一起使用。

答案 5 :(得分:0)

有很多解决方案。您还可以通过简单地添加表别名并加入列名来保留原始查询布局,在查询中您仍然只有DEPTNO = 20和JOB ='CLERK'。

SELECT 
  * 
FROM 
  scott.emp emptbl
WHERE
  emptbl.DEPTNO = 20 
  AND emptbl.JOB = 'CLERK'
  AND emptbl.SAL =  
    (
      select 
        max(salmax.SAL) 
      from 
        scott.emp salmax
      where 
        salmax.DEPTNO = emptbl.DEPTNO
        AND salmax.JOB = emptbl.JOB
    )

还可以注意到关键字“ALL”可用于这些类型的查询,这些查询允许您删除“MAX”功能。

SELECT 
  * 
FROM 
  scott.emp emptbl
WHERE
  emptbl.DEPTNO = 20 
  AND emptbl.JOB = 'CLERK'
  AND emptbl.SAL >= ALL  
    (
      select 
        salmax.SAL
      from 
        scott.emp salmax
      where 
        salmax.DEPTNO = emptbl.DEPTNO
        AND salmax.JOB = emptbl.JOB
    )

我希望这有帮助并且有意义。

相关问题