一. 原题呈现
牛客 SQL236. 删除emp_no重复的记录,只保留最小的id对应的记录。
描述:
删除emp_no重复的记录,只保留最小的id对应的记录。
drop table if exists titles_test;
CREATE TABLE titles_test (
id int(11) not null primary key,
emp_no int(11) NOT NULL,
title varchar(50) NOT NULL,
from_date date NOT NULL,
to_date date DEFAULT NULL);
insert into titles_test values
('1', '10001', 'Senior Engineer', '1986-06-26', '9999-01-01'),
('2', '10002', 'Staff', '1996-08-03', '9999-01-01'),
('3', '10003', 'Senior Engineer', '1995-12-03', '9999-01-01'),
('4', '10004', 'Senior Engineer', '1995-12-03', '9999-01-01'),
('5', '10001', 'Senior Engineer', '1986-06-26', '9999-01-01'),
('6', '10002', 'Staff', '1996-08-03', '9999-01-01'),
('7', '10003', 'Senior Engineer', '1995-12-03', '9999-01-01');
二. 题目分析与解答
1.高赞歧义解答
参考于【4】:
delete from titles_test where id not in(
select min(id) from titles_test group by emp_no
)
此方法思路是对的,但是在OJ中会出错,出错原因可参考第三章节。
2.join方法
delete from titles_test where id in(
select * from (
select t1.id from
titles_test t1 join titles_test t2
on t1.id > t2.id
where t1.emp_no = t2.emp_no
)t1
)
自连接,通过 t1.emp_no = t2.emp_no,筛选出t1.id > t2.id,并删除,此时依然需要额外用别表。
下面的解法依然会报错"You can't specify target table 'titles_test' for update in FROM clause"
delete from titles_test where id in(
select t1.id from
titles_test t1 join titles_test t2
on t1.id > t2.id
where t1.emp_no = t2.emp_no
)
3.group by妙用
在高赞歧义解答中,使用group by聚合每个emp_no中的最小值,以此来选出最小的id,在后续的操作中只需要选出不是最小id的条目即可。
三. "You can't specify target table 'titles_test' for update in FROM clause"
出错原因参考【1】:
简单来说就是 同表不支持 update 子查询的结果
而sqllite可以这样做
更改方法【2】:
delete from titles_test where id not in(
select * from(
select min(id) from titles_test group by emp_no
)t1
)
另外,t1的别名是不可省略的,否则会出错,可参考【3】:
ERROR 1248 (42000): Every derived table must have its own alias
简单来说就是 子查询的结果需要作为一个表交给上一层查询,需要列别名
参考来源
【1】博客园 缥缈之旅 ERROR 1093
【2】牛客 野生的桔子 SQL239
【3】爱佳男士 1248 - Every derived table must have its own alias (MYSQL错误)
【4】牛客 ciphersaw SQL239