繁体   English   中英

为什么我的 `delete where id in` 语句会删除表中的所有记录?

[英]why my `delete where id in` statement drop all records in the table?

我正在使用 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

这应该删除一条记录,但所有记录都被删除。

Actually there is a mistake in this SQL, the inner SQL select min(id) from reply group by ex_type and ex_id having count(1) > 1 return the result with only field: 'min(id)', outer sql select id from () tmp选择了一个不存在的字段 id 导致错误,但是 MySQL 仍然执行这个 sql 并删除所有记录。

我想知道为什么会这样。

您的查询在逻辑上是错误的。
这部分:

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 ,结果就是所有的行都被删除了。
您可以在此处查看此行为。
我相信这是你想要做的:

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
); 

...outer sql select id from () tmp a non exsit field id which lead to an error, but mysql execute this sql and delete all records.

我想知道为什么会这样。

此子查询不会自行运行:

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' */

但是当它在子查询中运行时,根据 scope 解析规则,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)... 都为真。 修复错字( 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
)

有趣 - 这似乎是一个错误,因为 DELETE 在这种情况下应该失败!

无论如何,只需将别名附加到 min(id) (并在 GROUP BY 之前删除那个奇怪的“和”),一切都会好起来的......(虽然,我不会这样写这个查询)

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 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM