MySQL - 更新列中的值与上一行相同的行

时间:2015-03-05 18:06:18

标签: mysql sql

我试图清理一些不正确的数据:

id   |   name
-------------
1    |   C
2    |   A
3    |   A
4    |   B
5    |   B
6    |   B
7    |   B
8    |   X
9    |   X
10   |   A   
11   |   A      
12   |   A
13   |   X
14   |   X
15   |   B
16   |   C
17   |   C
18   |   X
19   |   A
20   |   A

发生的事情是当输入数据时,如果name字段为NULL,则前一次循环迭代的值尚未清除,因此已输入下一行。

数据应如下所示:

id   |   name
-------------
1    |   C
2    |   A
3    |   NULL
4    |   B
5    |   NULL
6    |   NULL
7    |   NULL
8    |   X
9    |   NULL
10   |   A   
11   |   NULL     
12   |   NULL
13   |   X
14   |   NULL
15   |   B
16   |   C
17   |   NULL
18   |   X
19   |   A
20   |   NULL

有没有办法可以通过将所有重复项设置为NULL来一次更新整个表,同时保留列具有预期值的值?

3 个答案:

答案 0 :(得分:1)

我们需要将我们的副本加入到链中,通过以下方式轻松访问:

select *
from updateTable t1
left join updateTable t2 on t1.name = t2.name and t1.id+1 = t2.id
;
+----+------+------+------+
| id | name | id   | name |
+----+------+------+------+
|  1 | C    | NULL | NULL |
|  2 | A    |    3 | A    |
|  3 | A    | NULL | NULL |
|  4 | B    |    5 | B    |
|  5 | B    |    6 | B    |
|  6 | B    |    7 | B    |
|  7 | B    | NULL | NULL |
|  8 | X    |    9 | X    |
|  9 | X    | NULL | NULL |
| 10 | A    |   11 | A    |
| 11 | A    |   12 | A    |
| 12 | A    | NULL | NULL |
| 13 | X    |   14 | X    |
| 14 | X    | NULL | NULL |
| 15 | B    | NULL | NULL |
| 16 | C    |   17 | C    |
| 17 | C    | NULL | NULL |
| 18 | X    | NULL | NULL |
| 19 | A    |   20 | A    |
| 20 | A    | NULL | NULL |
+----+------+------+------+

现在我们知道应该更新的ID。
但我们不能跑:

update updateTable set name = null where id in (
    select t2.id
    from updateTable t1
    left join updateTable t2 on t1.name = t2.name and t1.id+1 = t2.id
    where t2.id is not null
);

因为我们会收到错误:

ERROR 1093 (HY000): You can't specify target table 'updateTable' for update in FROM clause

但我们可以通过使用临时表来执行ID来避免此错误:

create temporary table updateTableTmp (
    id int,
    primary key (id)
) engine=innodb;

insert into updateTableTmp
select t2.id
from updateTable t1
left join updateTable t2 on t1.name = t2.name and t1.id+1 = t2.id
where t2.id is not null
;

update updateTable set name = null where id in (
    select id from updateTableTmp
);

select * from updateTable;
+----+------+
| id | name |
+----+------+
|  1 | C    |
|  2 | A    |
|  3 | NULL |
|  4 | B    |
|  5 | NULL |
|  6 | NULL |
|  7 | NULL |
|  8 | X    |
|  9 | NULL |
| 10 | A    |
| 11 | NULL |
| 12 | NULL |
| 13 | X    |
| 14 | NULL |
| 15 | B    |
| 16 | C    |
| 17 | NULL |
| 18 | X    |
| 19 | A    |
| 20 | NULL |
+----+------+

答案 1 :(得分:0)

模仿每个名字的行号的用户变量。在我的机器上测试

SELECT @var:=name,@no:=0 FROM t ORDER BY id;
UPDATE t join
(select ID,NAME,(CASE WHEN NAME=@var THEN @no:=@no+1 ELSE @no:=1 AND @var:=NAME END) BLAH
from T
order by ID)X
on T.ID=X.ID
SET T.NAME= NULL
where X.BLAH<>0

答案 2 :(得分:0)

我有非常简单直接的解决方案。

只需获取每个记录的第一条记录,在更新时忽略它。 查询将如下所示:

UPDATE table SET name = NULL WHERE id NOT IN ( SELECT id FROM table WHERE name = 'A' LIMIT 1 )
相关问题