create table ithelp160812_dep (
dep_id smallserial primary key
, dep_name text
);
create table ithelp160812_emp (
emp_id smallint not null
, emp_name text
, dep_id smallint not null references ithelp160812_dep (dep_id)
);
insert into ithelp160812_dep values
(default, '殺雞部'),
(default, '拔毛部'),
(default, '裹粉部'),
(default, '油炸部');
select * from ithelp160812_dep;
+--------+----------+
| dep_id | dep_name |
+--------+----------+
| 1 | 殺雞部 |
| 2 | 拔毛部 |
| 3 | 裹粉部 |
| 4 | 油炸部 |
+--------+----------+
(4 rows)
insert into ithelp160812_emp values
(234, '大飛', 1),
(157, '號南', 1),
(283, '號北', 1),
(356, '號西', 1),
(765, '號東', 1),
(642, '號中', 1),
(577, '腥哥', 2),
(567, '細龜', 2),
(109, '馬仔', 2),
(255, '如花', 3),
(254, '如夢', 3),
(256, '如風', 3),
(258, '如如', 3),
(257, '如鈺', 3),
(755, '烽火', 4),
(754, '風火', 4),
(756, '陽炎', 4),
(758, '雪風', 4),
(757, '島風', 4);
--------------------------
使用 lateral join
select d.dep_id
, d.dep_name
, e.emp_id
, e.emp_name
from ithelp160812_dep d
join lateral (
select emp_id
, emp_name
from ithelp160812_emp e2
where e2.dep_id = d.dep_id
order by e2.emp_id
limit 5
) e
on true
order by d.dep_id;
+--------+----------+--------+----------+
| dep_id | dep_name | emp_id | emp_name |
+--------+----------+--------+----------+
| 1 | 殺雞部 | 157 | 號南 |
| 1 | 殺雞部 | 234 | 大飛 |
| 1 | 殺雞部 | 283 | 號北 |
| 1 | 殺雞部 | 356 | 號西 |
| 1 | 殺雞部 | 642 | 號中 |
| 2 | 拔毛部 | 109 | 馬仔 |
| 2 | 拔毛部 | 567 | 細龜 |
| 2 | 拔毛部 | 577 | 腥哥 |
| 3 | 裹粉部 | 254 | 如夢 |
| 3 | 裹粉部 | 255 | 如花 |
| 3 | 裹粉部 | 256 | 如風 |
| 3 | 裹粉部 | 257 | 如鈺 |
| 3 | 裹粉部 | 258 | 如如 |
| 4 | 油炸部 | 754 | 風火 |
| 4 | 油炸部 | 755 | 烽火 |
| 4 | 油炸部 | 756 | 陽炎 |
| 4 | 油炸部 | 757 | 島風 |
| 4 | 油炸部 | 758 | 雪風 |
+--------+----------+--------+----------+
(18 rows)
--------
使用 row_number
select emp_id
, emp_name
, row_number() over (partition by dep_id order by emp_id)
from ithelp160812_emp;
+--------+----------+------------+
| emp_id | emp_name | row_number |
+--------+----------+------------+
| 157 | 號南 | 1 |
| 234 | 大飛 | 2 |
| 283 | 號北 | 3 |
| 356 | 號西 | 4 |
| 642 | 號中 | 5 |
| 765 | 號東 | 6 |
| 109 | 馬仔 | 1 |
| 567 | 細龜 | 2 |
| 577 | 腥哥 | 3 |
| 254 | 如夢 | 1 |
| 255 | 如花 | 2 |
| 256 | 如風 | 3 |
| 257 | 如鈺 | 4 |
| 258 | 如如 | 5 |
| 754 | 風火 | 1 |
| 755 | 烽火 | 2 |
| 756 | 陽炎 | 3 |
| 757 | 島風 | 4 |
| 758 | 雪風 | 5 |
+--------+----------+------------+
(19 rows)
包起來取前五
select d.dep_id
, d.dep_name
, e.emp_id
, e.emp_name
from (select emp_id
, emp_name
, dep_id
, row_number() over (partition by dep_id order by emp_id) as rn
from ithelp160812_emp
) e
, ithelp160812_dep d
where d.dep_id = e.dep_id
and e.rn <= 5
order by d.dep_id, e.rn;
+--------+----------+--------+----------+
| dep_id | dep_name | emp_id | emp_name |
+--------+----------+--------+----------+
| 1 | 殺雞部 | 157 | 號南 |
| 1 | 殺雞部 | 234 | 大飛 |
| 1 | 殺雞部 | 283 | 號北 |
| 1 | 殺雞部 | 356 | 號西 |
| 1 | 殺雞部 | 642 | 號中 |
| 2 | 拔毛部 | 109 | 馬仔 |
| 2 | 拔毛部 | 567 | 細龜 |
| 2 | 拔毛部 | 577 | 腥哥 |
| 3 | 裹粉部 | 254 | 如夢 |
| 3 | 裹粉部 | 255 | 如花 |
| 3 | 裹粉部 | 256 | 如風 |
| 3 | 裹粉部 | 257 | 如鈺 |
| 3 | 裹粉部 | 258 | 如如 |
| 4 | 油炸部 | 754 | 風火 |
| 4 | 油炸部 | 755 | 烽火 |
| 4 | 油炸部 | 756 | 陽炎 |
| 4 | 油炸部 | 757 | 島風 |
| 4 | 油炸部 | 758 | 雪風 |
+--------+----------+--------+----------+
(18 rows)
一般是考Oracle Window Functions 會不會用,才出這題目.
Lateral Join 是比較新版的Oracle / PostgreSQL 才有的.
你去面試的公司,版本較舊的,就無法跑出來了.
找不到修改.....
create table ithelp160812_dep (
dep_id smallserial primary key
, dep_name text
);
create table ithelp160812_emp (
emp_id smallint not null
, emp_name text
, dep_id smallint not null references ithelp160812_dep (dep_id)
);
insert into ithelp160812_dep values
(default, '殺雞部'),
(default, '拔毛部'),
(default, '裹粉部'),
(default, '油炸部');
select * from ithelp160812_dep;
+--------+----------+
| dep_id | dep_name |
+--------+----------+
| 1 | 殺雞部 |
| 2 | 拔毛部 |
| 3 | 裹粉部 |
| 4 | 油炸部 |
+--------+----------+
(4 rows)
insert into ithelp160812_emp values
(234, '大飛', 1),
(157, '號南', 1),
(283, '號北', 1),
(356, '號西', 1),
(765, '號東', 1),
(642, '號中', 1),
(577, '腥哥', 2),
(567, '細龜', 2),
(109, '馬仔', 2),
(255, '如花', 3),
(254, '如夢', 3),
(256, '如風', 3),
(258, '如如', 3),
(257, '如鈺', 3),
(755, '烽火', 4),
(754, '風火', 4),
(756, '陽炎', 4),
(758, '雪風', 4),
(757, '島風', 4);
--------------------------
使用 lateral join
select d.dep_id
, d.dep_name
, e.emp_id
, e.emp_name
from ithelp160812_dep d
join lateral (
select emp_id
, emp_name
from ithelp160812_emp e2
where e2.dep_id = d.dep_id
order by e2.emp_id
limit 5
) e
on true
order by d.dep_id;
+--------+----------+--------+----------+
| dep_id | dep_name | emp_id | emp_name |
+--------+----------+--------+----------+
| 1 | 殺雞部 | 157 | 號南 |
| 1 | 殺雞部 | 234 | 大飛 |
| 1 | 殺雞部 | 283 | 號北 |
| 1 | 殺雞部 | 356 | 號西 |
| 1 | 殺雞部 | 642 | 號中 |
| 2 | 拔毛部 | 109 | 馬仔 |
| 2 | 拔毛部 | 567 | 細龜 |
| 2 | 拔毛部 | 577 | 腥哥 |
| 3 | 裹粉部 | 254 | 如夢 |
| 3 | 裹粉部 | 255 | 如花 |
| 3 | 裹粉部 | 256 | 如風 |
| 3 | 裹粉部 | 257 | 如鈺 |
| 3 | 裹粉部 | 258 | 如如 |
| 4 | 油炸部 | 754 | 風火 |
| 4 | 油炸部 | 755 | 烽火 |
| 4 | 油炸部 | 756 | 陽炎 |
| 4 | 油炸部 | 757 | 島風 |
| 4 | 油炸部 | 758 | 雪風 |
+--------+----------+--------+----------+
(18 rows)
--------
使用 row_number
select emp_id
, emp_name
, row_number() over (partition by dep_id order by emp_id)
from ithelp160812_emp;
+--------+----------+------------+
| emp_id | emp_name | row_number |
+--------+----------+------------+
| 157 | 號南 | 1 |
| 234 | 大飛 | 2 |
| 283 | 號北 | 3 |
| 356 | 號西 | 4 |
| 642 | 號中 | 5 |
| 765 | 號東 | 6 |
| 109 | 馬仔 | 1 |
| 567 | 細龜 | 2 |
| 577 | 腥哥 | 3 |
| 254 | 如夢 | 1 |
| 255 | 如花 | 2 |
| 256 | 如風 | 3 |
| 257 | 如鈺 | 4 |
| 258 | 如如 | 5 |
| 754 | 風火 | 1 |
| 755 | 烽火 | 2 |
| 756 | 陽炎 | 3 |
| 757 | 島風 | 4 |
| 758 | 雪風 | 5 |
+--------+----------+------------+
(19 rows)
包起來取前五
select d.dep_id
, d.dep_name
, e.emp_id
, e.emp_name
from (select emp_id
, emp_name
, dep_id
, row_number() over (partition by dep_id order by emp_id) as rn
from ithelp160812_emp
) e
, ithelp160812_dep d
where d.dep_id = e.dep_id
and e.rn <= 5
order by d.dep_id, e.rn;
+--------+----------+--------+----------+
| dep_id | dep_name | emp_id | emp_name |
+--------+----------+--------+----------+
| 1 | 殺雞部 | 157 | 號南 |
| 1 | 殺雞部 | 234 | 大飛 |
| 1 | 殺雞部 | 283 | 號北 |
| 1 | 殺雞部 | 356 | 號西 |
| 1 | 殺雞部 | 642 | 號中 |
| 2 | 拔毛部 | 109 | 馬仔 |
| 2 | 拔毛部 | 567 | 細龜 |
| 2 | 拔毛部 | 577 | 腥哥 |
| 3 | 裹粉部 | 254 | 如夢 |
| 3 | 裹粉部 | 255 | 如花 |
| 3 | 裹粉部 | 256 | 如風 |
| 3 | 裹粉部 | 257 | 如鈺 |
| 3 | 裹粉部 | 258 | 如如 |
| 4 | 油炸部 | 754 | 風火 |
| 4 | 油炸部 | 755 | 烽火 |
| 4 | 油炸部 | 756 | 陽炎 |
| 4 | 油炸部 | 757 | 島風 |
| 4 | 油炸部 | 758 | 雪風 |
+--------+----------+--------+----------+
(18 rows)
一般是考Oracle Window Functions 會不會用,才出這題目. Lateral Join 是比較新版的Oracle / PostgreSQL 才有的. 你去面試的公司,版本較舊的,就無法跑出來了.
在MS-SQL 中好像沒有 join lateral 這種JOIN方式(SQL-2008 以前的版本沒有)
個人認為比較好的方式 : 就是跑 WHILE 迴圈.
要用二層迴圈 : 第一層:部門 , 第二層:員工 先 INSERT 到 TEMP TABLE 後再 SELECT TEMP TABLE.
用 partition by 應該可以
請 google 下 sql partiton by 可以找到不少sample