我在MySQL中有这个表,例如:
ID | Name
1 | Bob
4 | Adam
6 | Someguy
如果您注意到,则没有身份证号码(2,3和5)。
如何编写查询以便MySQL只回答缺少的ID,在这种情况下:“2,3,5”?
答案 0 :(得分:23)
SELECT a.id+1 AS start, MIN(b.id) - 1 AS end
FROM testtable AS a, testtable AS b
WHERE a.id < b.id
GROUP BY a.id
HAVING start < MIN(b.id)
希望此链接也有帮助 http://www.codediesel.com/mysql/sequence-gaps-in-mysql/
答案 1 :(得分:21)
更有效的查询:
SELECT (t1.id + 1) as gap_starts_at,
(SELECT MIN(t3.id) -1 FROM my_table t3 WHERE t3.id > t1.id) as gap_ends_at
FROM my_table t1
WHERE NOT EXISTS (SELECT t2.id FROM my_table t2 WHERE t2.id = t1.id + 1)
HAVING gap_ends_at IS NOT NULL
答案 2 :(得分:3)
为了给Ivan的答案添加一点,这个版本显示如果1不存在则在开头缺少数字:
SELECT 1 as gap_starts_at,
(SELECT MIN(t4.id) -1 FROM testtable t4 WHERE t4.id > 1) as gap_ends_at
FROM testtable t5
WHERE NOT EXISTS (SELECT t6.id FROM testtable t6 WHERE t6.id = 1)
HAVING gap_ends_at IS NOT NULL limit 1
UNION
SELECT (t1.id + 1) as gap_starts_at,
(SELECT MIN(t3.id) -1 FROM testtable t3 WHERE t3.id > t1.id) as gap_ends_at
FROM testtable t1
WHERE NOT EXISTS (SELECT t2.id FROM testtable t2 WHERE t2.id = t1.id + 1)
HAVING gap_ends_at IS NOT NULL;
答案 3 :(得分:1)
如果不希望返回多个ID范围,而是要检索每个丢失的ID本身(每个ID都位于其自己的行中),则可以执行以下操作:
SELECT id+1 FROM table WHERE id NOT IN (SELECT id-1 FROM table) ORDER BY 1
查询非常有效。但是,它最后还包括一个额外的行,该行等于最大ID号加1。可以通过检查返回的行数(mysqli_num_rows)在服务器脚本中忽略最后一行。 ,然后如果行数大于1,则使用for
循环(查询将始终返回至少一行)。
编辑: 我最近发现,如果丢失的编号是连续的(即彼此相邻),我的原始解决方案不会 不 返回所有丢失的ID号。但是,该查询仍然非常有用,它可以非常快速地确定是否根本缺少数字,并且与hagensoft的查询(最佳答案)结合使用时,可以节省时间。换句话说,可以首先运行此查询以测试缺少的ID。如果找到任何内容,那么hagensoft的查询可以在此后立即运行,以帮助识别丢失的确切ID(不节省时间,但速度一点也不慢)。如果未找到任何内容,则可能会节省大量时间,因为无需运行hagensoft的查询。
答案 4 :(得分:0)
在一个查询中获得缺口的起点,在一个查询中获得缺口的终点会更加有效。
我有1800万条记录,并且每条记录花费不到一秒钟的时间即可获得两项结果。当我尝试将它们放在一起时,我的查询在一个小时后超时。
开始差距:
SELECT (t1.id + 1) as MissingID
FROM sequence t1
WHERE NOT EXISTS
(SELECT t2.id
FROM sequence t2
WHERE t2.id = t1.id + 1);
缩小差距:
SELECT (t1.id - 1) as MissingID
FROM sequence t1
WHERE NOT EXISTS
(SELECT t2.id
FROM sequence t2
WHERE t2.id = t1.id - 1);
答案 5 :(得分:0)
通过使用 window functions(在 mysql 8 中可用)
查找 id
列中的间隙可以表示为:
WITH gaps AS
(
SELECT
LAG(id, 1, 0) OVER(ORDER BY id) AS gap_begin,
id AS gap_end,
id - LAG(id, 1, 0) OVER(ORDER BY id) AS gap
FROM test
)
SELECT
gap_begin,
gap_end
FROM gaps
WHERE gap > 1
;
如果您使用的是旧版本的 mysql,您将不得不依赖变量(所谓的穷人窗口函数习惯用法)
SELECT
gap_begin,
gap_end
FROM (
SELECT
@id_previous AS gap_begin,
id AS gap_end,
id - @id_previous AS gap,
@id_previous := id
FROM (
SELECT
t.id
FROM test t
ORDER BY t.id
) AS sorted
JOIN (
SELECT
@id_previous := 0
) AS init_vars
) AS gaps
WHERE gap > 1
;
答案 6 :(得分:0)
如果您想要一种更轻松的方式来搜索数百万行数据,
SET @st=0,@diffSt=0,@diffEnd=0;
SELECT res.startID, res.endID, res.diff
, CONCAT(
"SELECT * FROM lost_consumer WHERE ID BETWEEN "
,res.startID+1, " AND ", res.endID-1) as `query`
FROM (
SELECT
@diffSt:=(@st) `startID`
, @diffEnd:=(a.ID) `endID`
, @st:=a.ID `end`
, @diffEnd-@diffSt-1 `diff`
FROM consumer a
ORDER BY a.ID
) res
WHERE res.diff>0;