本文根据网上常见的SQL面试题,删除除了自动编号不同, 其他都相同的学生冗余信息,给出分析和在GBase 8a数据库集群上的执行结果。
目录导航
题目
已知数据如下
gbase> select * from exam_2;
+------+------------+--------+----------+-----------+-------+
| id | student_id | name | class_Id | classname | score |
+------+------------+--------+----------+-----------+-------+
| 1 | 2005001 | 张三 | 0001 | 数学 | 69 |
| 2 | 2005002 | 李四 | 0001 | 数学 | 89 |
| 3 | 2005001 | 张三 | 0001 | 数学 | 69 |
+------+------------+--------+----------+-----------+-------+
3 rows in set (Elapsed: 00:00:00.01)
删除除了自动编号不同, 其他都相同的学生冗余信息。
分析
从数据看,id是自动编号,没有重复,而张三是存在重复的。但我们不能认定只有一次重复,答案里应考虑到出现多行重复的场景。
按照一般去重的方法,可以拿到最大或最小的ID,然后将其它列相同,但id不同的删除。
答案
通过not in删除
如下是先拿到其他列分组后,最大的编号 max(id),用min(id)也是可以的。然后将不属于这个集合的数据都删掉。
gbase> delete from exam_2 where id not in (select max(id) from exam_2 group by student_id,name,class_id,classname,score); Query OK, 1 row affected (Elapsed: 00:00:00.15)
gbase> select * from exam_2;
+------+------------+--------+----------+-----------+-------+
| id | student_id | name | class_Id | classname | score |
+------+------------+--------+----------+-----------+-------+
| 2 | 2005002 | 李四 | 0001 | 数学 | 89 |
| 3 | 2005001 | 张三 | 0001 | 数学 | 69 |
+------+------------+--------+----------+-----------+-------+
2 rows in set (Elapsed: 00:00:00.00)
关联删除
该方法是先拿到有重复值的max(id),然后通过多表关联删除的方法,将其它字段相等,但id小于max(id)的行删除。
gbase> select student_id,name,class_id,classname,score,max(id) from exam_2 group by student_id,name,class_id,classname,score having count(*) >1;
+------------+--------+----------+-----------+-------+---------+
| student_id | name | class_id | classname | score | max(id) |
+------------+--------+----------+-----------+-------+---------+
| 2005001 | 张三 | 0001 | 数学 | 69 | 3 |
+------------+--------+----------+-----------+-------+---------+
1 row in set (Elapsed: 00:00:00.05)
如下是完整SQL
gbase> delete a from exam_2 a inner join (select student_id,name,class_id,classname,score,max(id) maxid from exam_2 group by student_id,name,class_id,classname,score having count(*) >1)b on a.student_id=b.student_id and a.name=b.name and a.class_id=b.class_id and a.classname=b.classname and a.score=b.score and a.id<b.maxid;
Query OK, 1 row affected (Elapsed: 00:00:00.17)
gbase> select * from exam_2;
+------+------------+--------+----------+-----------+-------+
| id | student_id | name | class_Id | classname | score |
+------+------------+--------+----------+-----------+-------+
| 2 | 2005002 | 李四 | 0001 | 数学 | 89 |
| 3 | 2005001 | 张三 | 0001 | 数学 | 69 |
+------+------------+--------+----------+-----------+-------+
2 rows in set (Elapsed: 00:00:00.00)
总结
方法1语法简单容易理解,方法2语法复杂。但都是通过join的方式,将不匹配的删除。
在重复数据的比例极低时,比如1000用户万行里只有100用户重复的,则方法2可以减少一些join的数据负载。