テーブル構造
従業員
部門
CREATE TABLE `department` (
`id` int(0) NOT NULL,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
INSERT INTO `department` VALUES (1, 'IT 部门');
INSERT INTO `department` VALUES (2, '销售部门');
CREATE TABLE `employee` (
`id` int(0) NOT NULL,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`salary` int(0) NULL DEFAULT NULL,
`departmentId` int(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
INSERT INTO `employee` VALUES (1, 'joe', 70000, 1);
INSERT INTO `employee` VALUES (2, 'jim', 90000, 2);
INSERT INTO `employee` VALUES (3, 'heney', 80000, 2);
INSERT INTO `employee` VALUES (4, 'sam', 70000, 2);
INSERT INTO `employee` VALUES (5, 'kity', 60000, 1);
INSERT INTO `employee` VALUES (6, 'hellen', 68000, 1);
INSERT INTO `employee` VALUES (7, 'hym', 68000, 1);
INSERT INTO `employee` VALUES (8, 'liliy', 72000, 2);
1. 名のみをクエリする場合は、最も単純な方法を使用できます。
各部門の部門IDと1位の給与を問い合わせる
1.查询各个部门第一名的部门Id和薪资
SELECT departmentId,MAX(salary) departmentId FROM employee GROUP BY departmentId;
+--------------+--------------+
| departmentId | departmentId |
+--------------+--------------+
| 1 | 70000 |
| 2 | 90000 |
+--------------+--------------+
2.使用in
SELECT * FROM employee JOIN department on employee.departmentId = department.id
WHERE #双条件in
(employee.departmentId,employee.salary)
in #各部门第一名
(SELECT departmentId,MAX(salary) departmentId FROM employee GROUP BY departmentId) ;
+----+------+--------+--------------+----+--------------+
| id | name | salary | departmentId | id | name |
+----+------+--------+--------------+----+--------------+
| 1 | joe | 70000 | 1 | 1 | IT 部门 |
| 2 | jim | 90000 | 2 | 2 | 销售部门 |
+----+------+--------+--------------+----+--------------+
2. 上位 3 つをクエリする
1. まず、mysql のランキング関数、rank()、dense_rank()、row_number() の 3 つの関数を導入します。
Rank() は 1、2、2、4 としてソートされます。(同率2位のうち1名が3位となるため、3位は飛ばします。下図の順位は順位です)
name、詳細はid=6、7、5のランクを参照)
Partition by は、関数ソートの group by と同等です。
SELECT *,rank() over(partition by departmentId ORDER BY salary desc) ranks FROM employee;
+----+--------+--------+--------------+-------+
| id | name | salary | departmentId | ranks |
+----+--------+--------+--------------+-------+
| 1 | joe | 70000 | 1 | 1 |
| 6 | hellen | 68000 | 1 | 2 |
| 7 | hym | 68000 | 1 | 2 |
| 5 | kity | 60000 | 1 | 4 |
| 2 | jim | 90000 | 2 | 1 |
| 3 | heney | 80000 | 2 | 2 |
| 8 | liliy | 72000 | 2 | 3 |
| 4 | sam | 70000 | 2 | 4 |
+----+--------+--------+--------------+-------+
row_number()は行番号に従って 1、2、3、4 としてソートされます。
SELECT *,row_number() over(partition by departmentId ORDER BY salary desc) ranks FROM employee;
| id | name | salary | departmentId | ranks |
+----+--------+--------+--------------+-------+
| 1 | joe | 70000 | 1 | 1 |
| 6 | hellen | 68000 | 1 | 2 |
| 7 | hym | 68000 | 1 | 3 |
| 5 | kity | 60000 | 1 | 4 |
| 2 | jim | 90000 | 2 | 1 |
| 3 | heney | 80000 | 2 | 2 |
| 8 | liliy | 72000 | 2 | 3 |
| 4 | sam | 70000 | 2 | 4 |
Density_rank()は 1,2,2,3 としてソートされます。(denseは英語で「密な、稠密」を意味します。dense_rank()はソート番号が連続していて途切れないことを意味します)
SELECT *,dense_rank() over(partition by departmentId ORDER BY salary desc) ranks FROM employee;
| id | name | salary | departmentId | ranks |
+----+--------+--------+--------------+-------+
| 1 | joe | 70000 | 1 | 1 |
| 6 | hellen | 68000 | 1 | 2 |
| 7 | hym | 68000 | 1 | 2 |
| 5 | kity | 60000 | 1 | 3 |
| 2 | jim | 90000 | 2 | 1 |
| 3 | heney | 80000 | 2 | 2 |
| 8 | liliy | 72000 | 2 | 3 |
| 4 | sam | 70000 | 2 | 4 |
+----+--------+--------+--------------+-------+
2. mysql 関数を使用して上位 3 人の従業員をクエリします。
1.先查询出薪资排名
SELECT *,rank() over(partition by departmentId ORDER BY salary desc) ranks FROM employee;
| id | name | salary | departmentId | ranks |
+----+--------+--------+--------------+-------+
| 1 | joe | 70000 | 1 | 1 |
| 6 | hellen | 68000 | 1 | 2 |
| 7 | hym | 68000 | 1 | 2 |
| 5 | kity | 60000 | 1 | 4 |
| 2 | jim | 90000 | 2 | 1 |
| 3 | heney | 80000 | 2 | 2 |
| 8 | liliy | 72000 | 2 | 3 |
| 4 | sam | 70000 | 2 | 4 |
2.再根据已查出的薪资排名,筛选出前三名员工
SELECT * FROM department
JOIN (
SELECT *,rank() over(partition by departmentId ORDER BY salary desc) ranks FROM employee) a
on department.id = a.departmentId WHERE a.ranks <=3 ;
| id | name | id | name | salary | departmentId | ranks |
+----+--------------+----+--------+--------+--------------+-------+
| 1 | IT 部门 | 1 | joe | 70000 | 1 | 1 |
| 1 | IT 部门 | 6 | hellen | 68000 | 1 | 2 |
| 1 | IT 部门 | 7 | hym | 68000 | 1 | 2 |
| 2 | 销售部门 | 2 | jim | 90000 | 2 | 1 |
| 2 | 销售部门 | 3 | heney | 80000 | 2 | 2 |
| 2 | 销售部门 | 8 | liliy | 72000 | 2 | 3 |
3. 従来の方法を使用して上位 3 つをクエリします
1.查询出每个薪资数,比其它薪资数高的数量
select * from employee a,employee b where a.departmentId=b.departmentId and a.salary<b.salary;
このステートメントを翻訳すると、次のような意味になります。
70000未満の給与のレコードが3件あります
給与が 68000 未満のレコードが 2 件あります
。。。。。68000 が 2 つあるのに、なぜ 1 レコードが取得されなかったのか
給与が 60000 未満のレコードは 0 件あります
select * from employee a JOIN department ON a.departmentId = department.id
where (
select count(1) from employee where a.departmentId=departmentId and a.salary<salary) <3
order by a.departmentId, a.salary desc;
# where中select count(1) from employee where a.departmentId=departmentId and a.salary<salary) <3
整体查询时a.salary<salary 的意思是,employee的薪资比a中的高(注意:和之前的单独查询是意思不一样哦)
那么
当a中是70000是,count出来薪资比它高的数量是0条,小于3条 满足
当a中是68000是,count出来薪资比它高的数量是1条,小于3条 满足
当a中是60000是,count出来薪资比它高的数量是3条,等于3条 不满足
| id | name | salary | departmentId | id | name |
+----+--------+--------+--------------+----+--------------+
| 1 | joe | 70000 | 1 | 1 | IT 部门 |
| 6 | hellen | 68000 | 1 | 1 | IT 部门 |
| 7 | hym | 68000 | 1 | 1 | IT 部门 |
| 2 | jim | 90000 | 2 | 2 | 销售部门 |
| 3 | heney | 80000 | 2 | 2 | 销售部门 |
| 8 | liliy | 72000 | 2 | 2 | 销售部门 |