如何按性别选择first_name,最高工资组?

时间:2019-04-20 19:48:07

标签: sql oracle greatest-n-per-group

我有两个表tab1和tab2。

create table tab1 ( emp_id number(2), salary number(4));

insert into tab1 values(1,2000); 
insert into tab1 values(2,3000); 
insert into tab1 values(3,3645); 
insert into tab1 values(4,2143); 
insert into tab1 values(5,2541);

create table tab2( emp_id number(2), first_name varchar2(20), gender varchar2(10) );

insert into tab2 values(1,'aaaa','male'); 
insert into tab2 values(2,'bbbb','female'); 
insert into tab2 values(3,'cccc','male'); 
insert into tab2 values(4,'dddd','female'); 
insert into tab2 values(5,'eeee','male');

通过该查询,我只能获得性别和最高薪水列,但结果也希望看到emp_id和first_name列。这是我的查询...

select m.gender,max(h.salary) 
  from tab2 m 
  join tab1 h 
    on m.emp_id=h.emp_id 
 group by m.gender;

4 个答案:

答案 0 :(得分:2)

您是否需要在saubquery上加入最大薪水和性别

select  t1.emp_id, , t2.first_name, t.max_sal, t.gender 
from  tab1 t1 
inner join  tab2 t2 on t1.emp_id = t2.emp_id 
inner join  (
  select m.gender,max(h.salary) max_sal
  from tab2 m 
  join tab1 h on m.emp_id=h.emp_id 
  group by m.gender

) t on t.max_sal = t1.salary  and t.gender = t2.gender 

答案 1 :(得分:2)

像其他一些答案一样,两次读取tab2表是没有效率的,也没有必要。您可以使用通常称为MAX..KEEP的内容,但可以混淆使用FIRST函数(here)的文档。

此查询使用该功能为您提供所需的结果:

SELECT  t2.gender,
        max(t2.emp_id) keep ( dense_rank first order by t1.salary desc ) emp_id,
        max(t2.first_name) keep ( dense_rank first order by t1.salary desc ) first_name,
        max(t1.salary)
FROM    tab1 t1
INNER JOIN tab2 t2 ON t2.emp_id = t1.emp_id
GROUP BY t2.gender;

请注意,它仅读取每个表一次。

结果:

+--------+--------+------------+----------------+
| GENDER | EMP_ID + FIRST_NAME | MAX(T1.SALARY) |
+--------+--------+------------+----------------+
| female |      2 + bbbb       |           3000 |
| male   |      3 + cccc       |           3645 |
+--------+--------+------------+----------------+

我将断言这是获得您想要的结果的最有效方法。

[[我不喜欢在没有冗长的空间的情况下做出这样的陈述(如果您愿意,也可以说“狡猾的话”),因为那里的内容太多了,我们都需要学习。但是,如果有一种更快的方法来执行此查询,则值得学习对SO进行公开更正。 :)]

更新

顺便说一句,如果您有一个GENDERS表,像这样...

create table genders ( gender varchar2(10) );

insert into genders values ('male');
insert into genders values ('female');

那么这在12c及更高版本中也是一种合理的解决方案:

select g.gender, 
       ca.emp_id, 
       ca.first_name, 
       ca.salary 
from genders g  
CROSS APPLY ( SELECT t2.emp_id, 
                     t2.first_name, 
                     t2.gender, 
                     t1.salary
              FROM   tab1 t1 
              INNER JOIN tab2 t2 on t2.emp_id = t1.emp_id
              WHERE  t2.gender = g.gender
              ORDER BY t1.salary DESC
              FETCH FIRST 1 ROW ONLY ) ca

这种替代方法的好处是:

  1. 减少MAX..KEEP语法的重复,如果您不仅想要emp_idfirst_name,而且想要一堆其他列,那么可能会很麻烦
  2. 它可以受益于帮助CROSS APPLY中的查询的索引。对于您来说,GENDER上的索引可能没有足够的选择性来提供帮助,但是在其他情况下要牢记这一点。

答案 2 :(得分:0)

从tab1中选择tab2.gender,tab1.salary,tab1.emp_id,tab2.first_name加入tab1上的tab2.emp_id = tab2.emp_id其中tab1.salary =(从tab1中选择max(tab1.salary))

enter image description here

答案 3 :(得分:-2)

能否请您指定所需的预期结果,我不清楚。

你想得到这样的东西吗?
emp_id,名字,工资,性别

查询以按薪水排序的所有列

select h.emp_id, m.first_name, m.gender,h.salary from tab2 m join tab1 h on m.emp_id=h.emp_id order by h.salary desc;