MySQL从表中获取缺少的ID

时间:2012-09-07 20:44:27

标签: mysql

我在MySQL中有这个表,例如:

ID | Name
1  | Bob
4  | Adam
6  | Someguy

如果您注意到,则没有身份证号码(2,3和5)。

如何编写查询以便MySQL只回答缺少的ID,在这种情况下:“2,3,5”?

7 个答案:

答案 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;

看看这个http://sqlfiddle.com/#!9/3ea00c/9