考虑一下甲骨文 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。

有帮助吗?

解决方案

下面的内容有点过度设计,但对于“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查询获取最新价格

其他提示

如果我确定目标数据库,我会选择 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
)

*我相信这应该在任何地方都有效,但我没有环境来测试它。

在 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

那太棒了!我不知道您可以将 (x, y, z) 与 SELECT 语句的结果进行比较。这与 Oracle 配合得很好。

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

再次感谢马克。

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

例如...选择来自CUST的名称,数字(从BIG_TABLE中选择Cust_id),然后输入> sysdate -1会很慢。

但是选择名称,来自Cust的号码 C存在的位置(从big_table中选择cust_id 其中 cust_id=c.cust_id )并输入> sysdate -1将非常快速地使用正确的索引。您还可以将其与多个参数一起使用。

有很多解决方案。您还可以通过简单地添加表别名并加入列名称来保留原始查询布局,但查询中仍然只有 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
    )

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top