问题描述:
有一张表因为没有加重复判断,导致会有些重复数据存在,现在需要根据重复规则去掉重复的记录,只保留第一条。
解决方案:
1、两表自关联后按照主键删除,类似于Oracle的rowid
-- 删除主表 col是本表的主键
DELETE FROM tmp101 A
WHERE col NOT IN (SELECT MIN(col)
FROM tmp101 b
WHERE A.col1 = b.col1
AND A.col2 = b.col2
AND A.col3 = b.col3
AND A.col4 = b.col4);
2、采用inner join的方式找出需要删掉的数据
DELETE FROM tmp101 WHERE col1 in(
SELECT DISTINCT(a.col1) FROM tmp101 a
INNER JOIN tmp101 b
ON a.col1 = b.col1 AND a.col2 = b.col2
AND a.col3 = b.col3 AND a.col4 = b.col4
AND a.col > b.col);
[Err] 1093 - You can't specify target table 'tmp101' for update in FROM clause
MySQL就有一个很尴尬的地方,就是必须要把表包起来,才不报错。如下
DELETE FROM tmp101 WHERE col1 in(
SELECT * FROM(
SELECT DISTINCT(a.col1) FROM tmp101 a
INNER JOIN tmp101 b
ON a.col1 = b.col1 AND a.col2 = b.col2
AND a.col3 = b.col3 AND a.col4 = b.col4
AND a.col > b.col)a);
题外话:
在mysql8.0下是不支持row_number()over(partition by order by)的。
实现思路如下:
SELECT
IF(t1.id = @id and t1.name = @name,@rownum := @rownum + 1,@rownum := 1)AS rownum,
t1.*,
@id := t1.id,
@name := t1.name
FROM
(SELECT @rownum := 0,@id := NULL,@name := NULL) r,
test1 t1
ORDER BY t1.id,t1.name,t1.starttime DESC;
语法解析:
以id和starttime进行排序可以理解为id分组内starttime排序;
test1表关联@rownum :=0,@id :=null,在select中if判断@id是否等于当前行的id,因为初始为null,所以@rownum :=1,当id变化的时候,@id还是上一个id的值,此时@rownum重置为1,注意@id :=t1.id一定要放在if判断后面。
方案三:实现row_number
DELETE FROM tmp101 WHERE col1 in(
select col from(
select a.*,@rownum:=@rownum+1 rownum,
IF(@col1 = a.col1 AND @col2 = a.col2 AND @col3 = a.col3 AND @col4 = a.col4 ,
@rank := @rank + 1,
@rank := 1) AS rank,
@col1 := a.col1 , @col2 := a.col2 , @col3 := a.col3 , @col4 := a.col4
from (SELECT * FROM tmp101 ORDER BY col1,col2,col3,col4) a,
(select @col1 := null,@col2 := null,@col3 := null,@col4 := null,
@rownum:=null,@rank := null) tmp
) a WHERE rank <> 1) a;
小故事&#xff1a;
初次改写这个语句的时候&#xff0c;因为没有分清MySQL的&#61;和:&#61;导致查询出来解决不对。
下面简单科普下
MySQL的&#61;和:&#61;的区别。
&#61;只有在set和update时才是和:&#61;一样&#xff0c;赋值的作用&#xff0c;其它都是等于的作用。鉴于此&#xff0c;用变量实现行号时&#xff0c;必须用:&#61;
不只在set和update时起到赋值的作用&#xff0c;在select也是赋值的作用。
简单来说就是&#61;是等于的作用&#xff0c;判断相等。
:&#61;是赋值的作用。
如果用混了会导致结果不正确&#xff01;