我有以下表格:
create table employee(id int, name varchar(50), fname varchar(50));
create table rank (id int, name varchar(50));
create table promotion(id int, dt date, from_rank_id int, to_rank_id int, employee_id int,
constraint fk_pro_emp foreign key(employee_id) references employee(id),
constraint fk_pro_rank_f foreign key(from_rank_id) references rank(id),
constraint fk_pro_rank_t foreign key(to_rank_id) references rank(id));
insert into employee values(1, 'John', 'Roy'), (2, 'Kane', 'Williamson'), (3, 'Yasin', 'Khan'), (4, 'Dwayne', 'Brain');
insert into rank values(1, 'A'), (2, 'B'), (3, 'C'), (4, 'D'), (5, 'E');
--One person can have many promotions so I insert two records for the same person
insert into promotion values(1, '2010-01-01', 1, 2, 1), (2, '2015-01-01', 2, 3, 1);
--I insert three promotions for the second employee
insert into promotion values(4, '2011-11-23', 1, 2, 2), (5, '2012-04-05', 2, 3, 2), (6, '2013-12-30', 3, 4, 2);
--I insert one record for the third person
insert into promotion values(7, '2015-10-21', 3, 4, 3);
--The last person does not have promotion
现在我想从员工中选择记录及其最新(最长促销日期)促销记录 所需的输出是:
EMP_ID Name Father_Name Pro_Date From_Rank To_Rank
1 John Roy 2015-01-01 B C
2 Kane Williamson 2013-12-30 C D
3 Yasin Khan 2015-10-21 C D
4 Dwayne Brain <Null> <Null> <Null>
提前感谢您的帮助。
答案 0 :(得分:1)
在Postgres中解决greatest-n-per-group问题的常用方法是使用(专有)distinct on()
运算符。
以下查询返回每位员工的最新促销:
select distinct on (p.employee_id) p.employee_id
from promotion p
order by p.employee_id, p.dt desc
这可以与rank
表连接以获取等级名称:
select distinct on (p.employee_id) p.employee_id, p.dt as promotion_date, fr.name as from_rank, tr.name as to_rank
from promotion p
join rank tr on tr.id = p.to_rank_id
join rank fr on fr.id = p.from_rank_id
order by p.employee_id, p.dt desc
您的表格设置允许在没有from_rank_id
或to_rank_id
的情况下插入促销,因为这些列可以为空。如果确实允许(我怀疑),则需要将这些连接更改为外连接。至少应将to_rank_id
定义为NOT NULL
,但可能两者都定义为employee
。
该查询又可以加入select e.*, t.*
from employee e
left join (
select distinct on (p.employee_id) p.employee_id, p.dt as promotion_date, fr.name as from_rank, tr.name as to_rank
from promotion p
join rank tr on tr.id = p.to_rank_id
join rank fr on fr.id = p.from_rank_id
order by p.employee_id, p.dt desc
) t on t.employee_id = e.id
order by e.id;
表:
IWorker
答案 1 :(得分:0)
您可以使用LATERAL
加入和子查询,使用dt
为给定employee_id
选择最高ORDER BY dt DESC LIMIT 1
的促销,以获取曾晋升过一次的员工以及促销数据。 UNION ALL
从未晋升过的员工,您可以使用NOT EXISTS (SELECT * FROM promotion ...)
进行检查。
SELECT e.id "EMP_ID",
e.name "Name",
e.fname "Father_Name",
x.dt "Pro_Date",
x.rank_before "From_Rank",
x.rank_after "To_Rank"
FROM employee e
CROSS JOIN LATERAL (SELECT p.dt,
rb.name rank_before,
ra.name rank_after
FROM promotion p
LEFT JOIN rank rb
ON rb.id = p.from_rank_id
LEFT JOIN rank ra
ON ra.id = p.to_rank_id
WHERE p.employee_id = e.id
ORDER BY p.dt DESC
LIMIT 1) x
UNION ALL
SELECT e.id "EMP_ID",
e.name "Name",
e.fname "Father_Name",
NULL "Pro_Date",
NULL "From_Rank",
NULL "To_Rank"
FROM employee e
WHERE NOT EXISTS (SELECT *
FROM promotion p
WHERE p.employee_id = e.id);
答案 2 :(得分:0)
试试这个 -
SELECT e.id, e.name, e.fname, p3.dt pro_date, p3.name2 From_Rank, p3.name1 To_Rank
FROM employee e
left join (select p.dt dt, p.employee_id, r.name name1, r2.name name2
from promotion p
inner join (select max(dt) dt, employee_id
from promotion
group by employee_id) p2
on p.dt = p2.dt
left join rank r on p.to_rank_id = r.id
left join rank r2 on p.from_rank_id = r2.id) p3
on e.id = p3.employee_id