[英]MYSQL delete all rows, but the same query on select return only 3 rows
I can't understand why the same query for select and delete have different behavior. 我无法理解为什么select和delete的相同查询具有不同的行为。
I need to delete all rows except 5 newest rows. 我需要删除除5个最新行之外的所有行。
I know my solution for this task is no good, but my question is about why MySQL no delete the same rows, that return select for the same query clause 我知道我的这个任务的解决方案并不好,但我的问题是为什么MySQL没有删除相同的行,返回select为同一个查询子句
see code 看代码
drop table if exists tbl;
create table tbl
(
id serial,
cal date COMMENT 'some column',
created_at datetime default NOW()
);
insert into tbl
values
(default, '2018-07-15', '2018-07-15 12:00'),
(default, '2018-07-16', '2018-07-16 12:00'),
(default, '2018-07-17', '2018-07-17 12:00'),
(default, '2018-07-18', '2018-07-18 12:00'),
(default, '2018-08-01', '2018-08-01 12:00'),
(default, '2018-08-04', '2018-08-04 12:00'),
(default, '2018-08-16', '2018-08-16 12:00'),
(default, '2018-08-17', '2018-08-17 12:00');
select *
from tbl;
# +----+------------+---------------------+
# | id | cal | created_at |
# +----+------------+---------------------+
# | 1 | 2018-07-15 | 2018-07-15 12:00:00 |
# | 2 | 2018-07-16 | 2018-07-16 12:00:00 |
# | 3 | 2018-07-17 | 2018-07-17 12:00:00 |
# | 4 | 2018-07-18 | 2018-07-18 12:00:00 |
# | 5 | 2018-08-01 | 2018-08-01 12:00:00 |
# | 6 | 2018-08-04 | 2018-08-04 12:00:00 |
# | 7 | 2018-08-16 | 2018-08-16 12:00:00 |
# | 8 | 2018-08-17 | 2018-08-17 12:00:00 |
# +----+------------+---------------------+
now I need delete rows with id 1,2,3 现在我需要删除ID为1,2,3的行
SET @row_number = 0;
select *
from tbl
where tbl.id in (
select T.id
from (SELECT (@row_number := @row_number + 1) as num, tbl.id
from tbl
order by created_at desc
) as T
where T.num > 5);
# +----+------------+---------------------+
# | id | cal | created_at |
# +----+------------+---------------------+
# | 3 | 2018-07-17 | 2018-07-17 12:00:00 |
# | 2 | 2018-07-16 | 2018-07-16 12:00:00 |
# | 1 | 2018-07-15 | 2018-07-15 12:00:00 |
# +----+------------+---------------------+
Now I use delete operation 现在我使用删除操作
SET @row_number = 0;
delete
from tbl
where tbl.id in (
select T.id
from (SELECT (@row_number := @row_number + 1) as num, tbl.id
from tbl
order by created_at desc
) as T
where T.num > 5);
select * from tbl; # <-- result empty
# +----+-----+------------+
# | id | cal | created_at |
# +----+-----+------------+
I cry; 我哭了;
We can try doing a delete limit join here: 我们可以尝试在这里执行删除限制连接:
DELETE t1
FROM tbl t1
LEFT JOIN
(
SELECT id
FROM tbl
ORDER BY created_at DESC
LIMIT 5
) t2
ON t1.id = t2.id
WHERE
t2.id IS NULL;
The idea behind this anti-join is that we will delete any record which does not match to one of the first five records, as ordered descending by the created_at
column. 这种反连接背后的想法是,我们将删除任何与前五个记录之一不匹配的记录,这些记录按
created_at
列的顺序递减。
Note that we can't use a WHERE IN
query here, because MySQL will return the dreaded error message that LIMIT
is not yet supported in this version. 请注意,我们不能
WHERE IN
此处使用WHERE IN
查询,因为MySQL将返回此版本尚不支持LIMIT
的可怕错误消息。
Get the highest ID to delete using LIMIT
and OFFSET
: 使用
LIMIT
和OFFSET
获取要删除的最高ID:
set @last_id_to_delete = (
select id
from tbl
order by id desc
limit 1
offset 5
);
Then delete all rows with ID equal or smaller than the obove value: 然后删除ID等于或小于obove值的所有行:
delete tbl
from tbl
where id <= @last_id_to_delete;
You can combine the two queries into one. 您可以将两个查询合并为一个。 Either with a subquery in the WHERE clause:
使用WHERE子句中的子查询:
delete tbl
from tbl
where id <= (select id from(
select id
from tbl
order by id desc
limit 1
offset 5
)x);
(Note that you need to wrap the subquery result into a derived table, to avoid the error: "You can't specify target table 'tbl' for update in FROM clause".) (请注意,您需要将子查询结果包装到派生表中,以避免错误:“您无法在FROM子句中为更新指定目标表'tbl'。”
or by joining with a single-row subquery: 或者通过加入单行子查询:
delete t
from tbl t
join (
select id as last_id_to_delete
from tbl
order by id desc
limit 1
offset 5
) x on t.id <= x.last_id_to_delete;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.