题
考虑一下甲骨文 emp
桌子。我想让薪水最高的员工 department = 20
和 job = 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
)
我希望这有帮助并且有意义。