我正在使用MySQL 5.7.24版本。我想删除回复表中具有相同ex_id和ex_type的记录:
CREATE TABLE `reply` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`content` varchar(1024) NOT NULL,
`ex_id` bigint(20) DEFAULT '0',
`ex_type` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `idx_ex_id_type` (`ex_id`,`ex_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
具有以下数据:
+----+-------------------+-------+---------+
| id | content | ex_id | ex_type |
+----+-------------------+-------+---------+
| 1 | this is a content | 1 | 1 |
| 2 | this a test | 2 | 1 |
| 3 | this a contet | 1 | 1 |
| 4 | the 4th content | 3 | 1 |
+----+-------------------+-------+---------+
记录1和3共享相同的ex_id和ex_type,我想删除ID较小的记录(记录1),所以我编写了以下查询:
delete from reply where id in (
select id from (
select min(id) from reply group by ex_type and ex_id having count(1) > 1
) tmp
)
-- Query OK, 4 rows affected
这应该删除一条记录,但是所有记录都将被删除。
实际上此SQL中有一个错误,内部SQL select min(id) from reply group by ex_type and ex_id having count(1) > 1
返回仅包含字段的结果:'min(id)',外部SQL select id from () tmp
选择一个不存在的字段ID,从而导致错误,但MySQL仍执行此sql并删除所有记录。
我想知道为什么会这样。
答案 0 :(得分:1)
您的查询在逻辑上是错误的。
这部分:
select min(id) from reply group by ex_type and ex_id having count(1) > 1
按ex_type and ex_id
而不是ex_type, ex_id
分组。
最重要的是,它不会返回名为/别名为id
的列。
这样:
select id from...
实际上是引用该表的id
并返回该表的id
的 all ,结果是所有行均被删除。
您可以看到此行为here。
我相信这就是您想要做的:
delete from reply where id in
(
select id from (
select min(id) id from reply group by ex_type, ex_id having count(*) > 1
) tmp
);
答案 1 :(得分:1)
...外部sql
select id from () tmp
选择不存在的字段ID 导致错误,但是mysql执行此sql并删除所有 记录。我想知道为什么会这样。
此子查询将不会单独运行:
select id from (
select min(id) from reply group by ex_type and ex_id having count(1) > 1
) tmp
/* SQL Error (1054): Unknown column 'id' in 'field list' */
但是当它在子查询中运行时,根据作用域解析规则, id列解析为外部查询的id列,因为FROM子句中不存在所请求的列 。查询本质上是这样的:
delete from reply where id in (
select reply.id from (
select min(id) from reply group by ex_type and ex_id having count(1) > 1
) tmp
)
/* Affected rows: 4 Found rows: 0 Warnings: 0 Duration for 1 query: 0.031 sec. */
由于1 IN(1),2 IN(2),3 IN(3)...都为真,因此所有行的条件均为true。修正拼写错误(group by ex_type and ex_id
)不会解决问题,请将查询更改为此:
delete from reply where id in (
select tmp.id from (
select min(id) as id from reply group by ex_type, ex_id having count(1) > 1
) tmp
)
答案 2 :(得分:0)
有趣-这似乎是一个错误,因为在这种情况下DELETE应该失败!
无论如何,只要在min(id)上附加一个别名(并在GROUP BY之前删除那个奇怪的'and'),一切都会好起来的...(尽管我不会这样写查询) / p>
DROP TABLE IF EXISTS reply;
CREATE TABLE `reply` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`content` varchar(1024) NOT NULL,
`ex_id` bigint(20) DEFAULT '0',
`ex_type` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `idx_ex_id_type` (`ex_id`,`ex_type`)
);
INSERT INTO reply VALUES
(1,'this is a content',1,1),
(2,'this a test',2,1),
(3,'this a contet',1,1),
(4,'the 4th content',3,1);
delete from reply where id in
(
select id from (
select min(id) id from reply group by ex_type, ex_id having count(1) > 1
) tmp
);
SELECT * FROM reply;
+----+-----------------+-------+---------+
| id | content | ex_id | ex_type |
+----+-----------------+-------+---------+
| 2 | this a test | 2 | 1 |
| 3 | this a contet | 1 | 1 |
| 4 | the 4th content | 3 | 1 |
+----+-----------------+-------+---------+
FWIW,对于较小的数据集,我可能会以这种方式编写该查询...
DELETE r
FROM reply r
JOIN
( SELECT MIN(id) id
FROM reply
GROUP
BY ex_type
, ex_id
HAVING COUNT(0) > 1
) x
ON x.id = r.id