【发布时间】:2020-06-24 08:46:34
【问题描述】:
我有一个包含 ID 的表。
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 6 |
| 9 |
| 7 |
| 10 |
5 号和 8 号不在表中。 我只想从表中选择那些行
【问题讨论】:
标签: mysql sql phpmyadmin
我有一个包含 ID 的表。
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 6 |
| 9 |
| 7 |
| 10 |
5 号和 8 号不在表中。 我只想从表中选择那些行
【问题讨论】:
标签: mysql sql phpmyadmin
如果你想要缺少ids,一个选项是递归查询来生成号码列表,然后not exists(这需要MySQL 8.0):
with cte as (
select min(id) id, max(id) max_id from mytable
union all
select id + 1, max_id from cte where id < max_id
)
select c.id
from cte c
where not exists (select 1 from mytable t where t.id = c.id)
【讨论】:
您可以通过查看上一行来找出差距。如果您的表不是太大:
select (t.prev_id + 1) as first_missing,
(t.id - 1) as last_missing,
(t.id - t.prev_id - 1) as cnt
from (select t.*,
(select max(t2.id)
from t t2
where t2.id < t.id
) as prev_id
from t
) t
where t.prev_id <> t.id - 1;
实际上,在早期版本的 MySQL 中,将其拆分为单独的行是很棘手的,除非您有一个数字或计数表。
如果你的数据很大,你可以改用变量:
select (t.prev_id + 1) as first_missing,
(t.id - 1) as last_missing,
(t.id - t.prev_id - 1) as cnt
from (select t.*,
(case when (@temp := @prev) = null
then null -- never happens
when (@prev := id) = null
then null -- never happens
else @temp
end) as prev_id
from (select t.* from t order by id) t cross join
(select @prev := -1) params
) t
where t.prev_id <> t.id - 1;
【讨论】:
In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 't.prev_id'; this is incompatible with sql_mode=only_full_group_by。我假设是 count(*) as cnt 导致它。
SELECT MIN(id) - 1 id
FROM ( SELECT id, id - @group_number:=@group_number + 1 group_number
FROM test, (SELECT @group_number := 0) init_variable
ORDER BY id ) subquery
GROUP BY group_number
HAVING id;
如果有很多连续丢失的号码,只会退回最后一个。
【讨论】: