目录
1.找类别最高值
错误的查询方式:
(看看都会写写全错版T^T)
SELECT department.name AS Department, employee.name AS Employee, employee.salary AS Salary
FROM employee
JOIN department ON employee.departmentId = department.id
GROUP BY department.id
HAVING MAX(salary);
问题分析
在GROUP BY
和SELECT
列不一致:SELECT
中选择了department.name
、employee.name
和employee.salary
,但在GROUP BY
中只按department.id
分组。这会导致语法错误,因为GROUP BY
后的列必须与SELECT
中的非聚合列一致。HAVING
子句的使用:HAVING MAX(salary)
是不合法的,因为HAVING
子句需要一个条件来过滤分组结果。没有提供一个具体的条件,只是写了MAX(salary)
。逻辑问题:
目标是筛选每个部门的最高工资员工,但当前的查询逻辑无法实现这一点。需要先找到每个部门的最高工资,然后再关联员工表来获取对应的员工信息。
正确的查询方式:
使用子查询
select department.name as Department,employee.name as Employee,employee.salary as Salary
from employee
join department on employee.departmentId = department.id
where (employee.salary,employee.departmentId) in(
select max(salary),departmentId
from employee
group by departmentId
)
子查询
SELECT departmentId, MAX(salary) FROM Employee GROUP BY departmentId
找到每个部门的最高工资。外层查询通过
WHERE (departmentId, salary) IN (...)
筛选出这些最高工资对应的员工。
使用窗口函数(MySQL8.X支持)
SELECT Department, Employee, Salary
FROM (
SELECT
d.name AS Department,
e.name AS Employee,
e.salary AS Salary,
RANK() OVER (PARTITION BY d.id ORDER BY e.salary DESC) AS rank
FROM Employee e
JOIN Department d ON e.departmentId = d.id
) AS ranked_employees
WHERE rank = 1;
使用窗口函数
RANK()
,对每个部门的员工按工资降序排名。
PARTITION BY employee.departmentId
:按departmentId
分组
ORDER BY employee.salary DESC
:按工资降序排列,工资最高的员工排名为1。
外层查询筛选出排名为1的员工,即每个部门的最高工资员工。
扩展:查找类别前N高的值
185. 部门工资前三高的所有员工 - 力扣(LeetCode)
使用方法2窗口函数进行推广
/* Write your T-SQL query statement below */
SELECT Department, Employee, Salary
FROM (
SELECT
d.name AS Department,
e.name AS Employee,
e.salary AS Salary,
dense_RANK() OVER (PARTITION BY d.id ORDER BY e.salary DESC) AS rank
FROM Employee e
JOIN Department d ON e.departmentId = d.id
) AS ranked_employees
WHERE rank <= 3;
2.删除重复值并保留最小序号
delete实现
-- 用自连接:
delete p1
from person p1
join person p2 on p1.email=p2.email and p1.id>p2.id
-- 不用自连接
DELETE p1 FROM Person p1,
Person p2
WHERE
p1.Email = p2.Email AND p1.Id > p2.Id
筛选无重复且序号最小值
select——where in
SELECT id, email
FROM person
WHERE (email, id) IN (
SELECT email, MIN(id)
FROM person
GROUP BY email
);
子查询:
SELECT email, MIN(id) FROM Person GROUP BY email
找到每个id
。这个子查询的结果是一个临时表,包含每个id
。主查询:通过
WHERE (email, id) IN (...)
筛选出Person
表中那些id
匹配子查询结果的记录。
select——join&子查询
SELECT p1.id, p1.email
FROM person p1
JOIN (
SELECT email, MIN(id) AS min_id
FROM person
GROUP BY email
) p2 ON p1.email = p2.email AND p1.id = p2.min_id;
子查询:
SELECT email, MIN(id) AS min_id FROM person GROUP BY email
找到每个id
。这个子查询的结果是一个临时表p2
,包含每个id
。主查询:通过
JOIN
将person
表和子查询的结果p2
连接起来,条件是p1.email = p2.email AND p1.id = p2.min_id
,这样可以筛选出每个id
对应的记录。
(select力扣上运行不了但我觉得逻辑上是这样)
3.找带条件的连续值
窗口函数实现
# Write your MySQL query statement below
select id as Id from (
select id,temperature,recordDate,
LAG(temperature,1) over (order by recordDate) as pre_temperature,
LAG(recordDate,1) over (order by recordDate) as pre_recordDate
from weather
) as queryweather
where pre_temperature<temperature and DATEDIFF(recordDate,pre_recordDate)=1
子查询:
LAG(temperature, 1) OVER (ORDER BY recordDate) AS pre_temperature
:获取前一天的温度。LAG(recordDate, 1) OVER (ORDER BY recordDate) AS pre_recordDate
:获取前一天的日期。主查询:
WHERE pre_temperature < temperature
:确保当前温度高于前一天的温度。AND DATEDIFF(recordDate, pre_recordDate) = 1
:确保当前日期和前一天的日期是连续的。
日期比较函数
DATEDIFF()
:计算两个日期之间的天数差SELECT DATEDIFF('2025-05-18', '2025-05-10') AS days_difference;
DATE_ADD()
和DATE_SUB()
:在日期上加上或减去指定的时间间隔SELECT DATE_ADD('2025-05-18', INTERVAL 10 DAY) AS future_date; SELECT DATE_SUB('2025-05-18', INTERVAL 10 DAY) AS past_date;
后面两题都用到了之前遇到过的知识点,就不过多赘述啦
(其实是靠自己写出来了 嘿嘿,虽然他们都是简单的题)
4.
select customer_number
from (
select customer_number,count(*) as cn
from orders
group by customer_number
order by cn DESC
) as subquery
limit 1
5.
select player_id,event_date as first_login
from activity
where (player_id,event_date) in(
select player_id,min(event_date)
from activity
group by player_id
)