Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL:在表中查找缺少的ID_Sql - Fatal编程技术网

SQL:在表中查找缺少的ID

SQL:在表中查找缺少的ID,sql,Sql,我有一个具有唯一自动增量主键的表。随着时间的推移,条目可能会从表中删除,因此此字段的值中存在漏洞。例如,表数据可以如下所示: ID | Value | More fields... --------------------------------- 2 | Cat | ... 3 | Fish | ... 6 | Dog | ... 7 | Aardvark | ... 9 | Owl | ... 10 | Pi

我有一个具有唯一自动增量主键的表。随着时间的推移,条目可能会从表中删除,因此此字段的值中存在漏洞。例如,表数据可以如下所示:

 ID  | Value    | More fields...
---------------------------------
 2   | Cat      | ... 
 3   | Fish     | ...
 6   | Dog      | ...
 7   | Aardvark | ...
 9   | Owl      | ...
 10  | Pig      | ...
 11  | Badger   | ...
 15  | Mongoose | ...
 19  | Ferret   | ...
我对返回表中缺失ID列表的查询感兴趣。对于上述数据,预期结果如下:

 ID 
----
 1
 4
 5
 8
 12
 13
 14
 16
 17
 18
注:

假设初始第一个ID为1 应该检查的最大ID是最后一个,也就是说,可以假设在当前最后一个ID之后没有其他条目。请参阅下面关于这一点的其他数据 上述要求的一个缺点是,列表不会返回在ID 19之后创建并已删除的ID。我目前正在用代码解决这个问题,因为我持有创建的max ID。但是,如果查询可以将MaxID作为参数,并返回当前max和MaxID之间的id,这将是一个不错的奖励,但肯定不是必须的


我目前正在使用MySQL,但是考虑移动到SQLServer,所以我希望查询适合两者。另外,如果您使用的是无法在SQLite上运行的任何东西,请提及,谢谢。

这个问题经常出现,遗憾的是,最常见和最方便的答案是创建一个临时表来保存应该在那里的ID,并进行左连接。MySQL和SQL Server之间的语法非常相似。唯一真正的区别是临时表语法

在MySQL中:

declare @id int
declare @maxid int

set @id = 1
select @maxid = max(id) from tbl

create temporary table IDSeq
(
    id int
)

while @id < @maxid
begin
    insert into IDSeq values(@id)

    set @id = @id + 1
end

select 
    s.id 
from 
    idseq s 
    left join tbl t on 
        s.id = t.id 
 where t.id is null

 drop table IDSeq
在SQL Server中:

declare @id int
declare @maxid int

set @id = 1
select @maxid = max(id) from tbl

create table #IDSeq
(
    id int
)

while @id < @maxid --whatever you max is
begin
    insert into #IDSeq values(@id)

    set @id = @id + 1
end

select 
    s.id 
from 
    #idseq s 
    left join tbl t on 
        s.id = t.id 
 where t.id is null

 drop table #IDSeq
;WITH Missing (missnum, maxid)
AS
(
 SELECT 1 AS missnum, (select max(id) from @TT)
 UNION ALL
 SELECT missnum + 1, maxid FROM Missing
 WHERE missnum < maxid
)
SELECT missnum
FROM Missing
LEFT OUTER JOIN @TT tt on tt.id = Missing.missnum
WHERE tt.id is NULL
OPTION (MAXRECURSION 0); 

以下是对SQL Server的查询:

declare @id int
declare @maxid int

set @id = 1
select @maxid = max(id) from tbl

create table #IDSeq
(
    id int
)

while @id < @maxid --whatever you max is
begin
    insert into #IDSeq values(@id)

    set @id = @id + 1
end

select 
    s.id 
from 
    #idseq s 
    left join tbl t on 
        s.id = t.id 
 where t.id is null

 drop table #IDSeq
;WITH Missing (missnum, maxid)
AS
(
 SELECT 1 AS missnum, (select max(id) from @TT)
 UNION ALL
 SELECT missnum + 1, maxid FROM Missing
 WHERE missnum < maxid
)
SELECT missnum
FROM Missing
LEFT OUTER JOIN @TT tt on tt.id = Missing.missnum
WHERE tt.id is NULL
OPTION (MAXRECURSION 0); 

希望这有帮助。

这是一个仅限Oracle的解决方案。它没有解决完整的问题,但留给其他可能正在使用Oracle的人

select level id           -- generate 1 .. 19
from dual
connect by level <= 19

minus                     -- remove from that set

select id                 -- everything that is currently in the 
from table                -- actual table

我知道这是个老问题,已经有了公认的答案, 但是使用临时表并不是真正必要的。修正了双贴的格式问题

DECLARE @TEST_ID integer, @LAST_ID integer, @ID integer

SET @TEST_ID = 1 -- start compare with this ID 
SET @LAST_ID = 100 -- end compare with this ID

WHILE @TEST_ID <= @LAST_ID 
BEGIN 
  SELECT @ID = (SELECT <column> FROM <table> WHERE <column> = @TEST_ID) 
  IF @ID IS NULL 
  BEGIN 
    PRINT 'Missing ID: ' + CAST(@TEST_ID AS VARCHAR(10)) 
  END 
  SET @TEST_ID = @TEST_ID + 1 
END

单个查询可以找到缺少的ID

SELECT distinct number

FROM master..spt_values

WHERE number BETWEEN 1 and (SELECT max(id) FROM MyTable)

AND number NOT IN (SELECT id FROM MyTable)

更新:此方法花费的时间太长,所以我编写了一个linux命令来查找文本文件中的空白。它以相反的顺序执行,因此首先将所有id转储到一个文本文件中,如下所示

nohup mysql --password=xx -e 'select id from tablename order by id desc' databasename > /home/ids.txt &
第一行和最后两行只是为了记录花了多长时间。150万IDsish花了我57秒&这是在一台速度较慢的服务器上。在i中设置最大id,并对其进行调整

T="$(date +%s)"; \
i=1574115; \
while read line; do \
    if  [[ "$line" != "$i" ]] ; then \
        if [[ $i -lt 1 ]] ; then break; fi; \
        if  [[ $line -gt 1 ]] ; then \
            missingsequenceend=$(( $line + 1 )); \
            minusstr="-"; \
            missingsequence="$missingsequenceend$minusstr$i"; \
            expectnext=$(( $line - 1 )); \
            i=$expectnext; \
            echo -e "$missingsequence"; \
        fi; \
    else \
        i=$(( $i - 1 )); \
    fi; \
done \
< /home/ids.txt; \
T="$(($(date +%s)-T))"; \
echo "Time in seconds: ${T}"
另外,我从Eric的答案中得到了代码的语法错误,但是在更改分隔符、在适当的位置使用分号并将其存储在过程中之后,它就工作了

确保在select查询中设置了正确的max ID、数据库名称和表名称。如果要更改过程名称,请在所有3个位置进行更改

use dbname;
drop procedure if exists dorepeat;
delimiter #
CREATE PROCEDURE dorepeat()
BEGIN
set @id = 1;
set @maxid = 1573736;
drop table if exists IDSeq;
create temporary table IDSeq
(
    id int
);

WHILE @id < @maxid DO
    insert into IDSeq values(@id);
    set @id = @id + 1;
END WHILE;

select 
    s.id 
from 
    IDSeq s 
    left join tablename t on 
        s.id = t.id 
 where t.id is null;

drop table if exists IDSeq;

END#
delimiter ;
CALL dorepeat;
我在哪里也找到了这个查询,但是我还没有测试它

SELECT a.id+1 AS start, MIN(b.id) - 1 AS end
    FROM tablename AS a, tablename AS b
    WHERE a.id < b.id
    GROUP BY a.id
    HAVING start < MIN(b.id)

这个问题只需要一个查询就可以解决

select lft.id + 1 as missing_ids
from tbl as lft left outer join tbl as rght on lft.id + 1 = rght.id
where rght.id is null and lft.id between 1 and (Select max(id)-1 from tbl)
在Mysql上测试

在Mysql中尝试

尝试此查询。这一个查询足以获取缺少的数字:请将您正在使用的表名替换为表名


这就是我用来查找一个名为tablename的表缺少的id的原因

从表名a中选择a.id+1缺少\u id 其中a.id+1不在表名b中,从表名b中选择id,其中b.id=a.id+1 还有a.id=从tablename c中选择id按id顺序描述限制1

它将返回丢失的ID。
如果有两个或两个以上连续丢失的ID,它将只返回第一个

几天前,我正在写生产报告,发现一些数字不见了。丢失的号码非常重要,所以我被要求查找所有丢失号码的列表,以便进行调查

建议的脚本相当长,因此我不会在这里包含它。以下是使用的基本步骤:

创建一个临时表并存储所有不同的数字。 查找之前缺少某些内容的NextID。储存在一个诱人的地方。 创建一个临时表以存储丢失的号码详细信息。 开始使用WHILE循环查找缺少的id。 从MissingID临时表中选择缺少的数据。
我登陆这个页面,希望找到一个SQLITE的解决方案,因为这是我在搜索SQLITE的这个问题时找到的唯一答案

我找到的最终解决方案来自本文

希望它能帮助其他人:-

简单的解决办法是:

SELECT DISTINCT id +1
FROM mytable
WHERE id + 1 NOT IN (SELECT DISTINCT id FROM mytable);

genius.

将SQL CTE从Paul Swirin转换为Oracle版本它看起来像这样:用表的名称替换:YOURTABLE:

WITH Missing (missnum,maxid) as (
  SELECT 1 missnum, (select max(id) from :YOURTABLE) maxid from dual
  UNION ALL
  SELECT m.missnum + 1,m.maxid 
  FROM Missing m
  WHERE m.missnum < m.maxid
)
SELECT missnum
FROM Missing
LEFT OUTER JOIN :YOURTABLE tt on tt.id = Missing.missnum
WHERE tt.id is NULL
使用@PaulSvirin的答案,我用一个并集对其进行了扩展,以显示表中的所有数据,包括带有null的缺失记录


仅限PostgreSQL,受其他答案启发

SELECT all_ids AS missing_ids
FROM generate_series((SELECT MIN(id) FROM your_table), (SELECT MAX(id) FROM your_table)) all_ids
EXCEPT 
SELECT id FROM your_table
从表中获取缺少的行

说明:id-1。。。。。检查表中是否存在任何以前的id


身份证!=1..忽略当前id为1时,因为其上一个id将为0 0。

对我来说最简单的解决方案:创建一个选择,使所有id的最大序列值为ex:1000000,并进行筛选:

with listids as (
Select Rownum idnumber From dual Connect By Rownum <= 1000000)

select * from listids
where idnumber not in (select id from table where id <=1000000)

我刚刚找到了Postgres的解决方案:

选择明 自1999年1月1日起,作为gs 其中gs不在从中选择id中 空白表

我不确定在这种环境下会发生什么情况,但如果不是20条,而是1000条记录呢。。这是由同时服务50-60个用户的网页上的代码调用的。每次创建和删除这些记录是否有效?考虑到我们忽略了创建临时表的部分,并放弃了临时表。@daemonkid:伙计,真是个该死的吸管工。如果您必须一次又一次地解决这个问题,对于50-60个用户,您显然需要一个永久表。显然你必须适应你的特定场景,但是这是找到失踪ID的问题的解决方案。+ 1,我不确定我会同意,但我会考虑。谢谢Eric。虽然它可以处理示例数据,但对于大量记录来说并不好。如果需要大于100.000的范围,仅while一项就需要几秒钟才能完成。它非常适合大量记录。我已经将它与一个包含600k条记录的表上的另一个答案进行了比较。MySQL上的可比较查询是什么?这只会找到比现有ID大1的缺失ID。在OPs的情况下,它会丢失大部分丢失的ID。注意:此答案特定于SQL Server。。不适用于MS SQL Server 2008。表包含600k条记录,此查询仅检查2150条。@naXa这是因为spt_值只是一个包含一组随机数的表。这个答案是完全错误的。@Stijn正是我所暗示的,所以我投了反对票,因为我帮助了一个可能会像我一样登上这一页的人。很好。一年多以后,我可以建议一个小的改进,它消除了SQLITE中返回的最大缺失值(总是maxid+1):只需在查询结束时添加:id<从mytable中选择maxid;[希望它能帮助像你帮助我一样的人]这只是部分起作用。如果您有ID 24,但不是25或26,则此请求将获得ID 25,但不是ID 26,因此您将忘记修复ID 26的情况。搜索了数小时,发现了许多复杂的解决方案。这是一个多么简单和天才的回答啊。这对我帮助很大。非常感谢@NikBurns这是最快的一个,Nik Burns接受的答案更精确,因此,如果您正在构建一个自动化的解决方案,这是非常理想的。对于小桌子和手工工作来说,这是理想的。这不是一个简单的问题。我发现这对博士后来说非常有用。生成_系列函数的链接如下所示:。我很高兴我找到了这个解决方案。谢谢!出于某种原因,id以一种非常随机的顺序出现,因此我在末尾添加了缺少\u id的顺序。稍微改进以获取所有缺少的id:从generate\u series1中选择gs,从mytable中选择MAXid作为gs,其中gs不在从mytable中选择id
TETmeetingID    DateID  WeekNo  TETID
29  3063    21  1
30  null    null    null
31  null    null    null
32  null    null    null
33  null    null    null
34  3070    22  1
35  3073    23  1
SELECT all_ids AS missing_ids
FROM generate_series((SELECT MIN(id) FROM your_table), (SELECT MAX(id) FROM your_table)) all_ids
EXCEPT 
SELECT id FROM your_table
DECLARE @MaxID INT = (SELECT MAX(ID) FROM TABLE1)
SELECT SeqID AS MissingSeqID
FROM (SELECT ROW_NUMBER() OVER (ORDER BY column_id) SeqID from sys.columns) LkUp
LEFT JOIN dbo.TABLE1 t ON t.ID = LkUp.SeqID
WHERE t.ID is null and SeqID < @MaxID
SELECT DISTINCT id -1
FROM users
WHERE id != 1 AND id - 1 NOT IN (SELECT DISTINCT id FROM users)
with listids as (
Select Rownum idnumber From dual Connect By Rownum <= 1000000)

select * from listids
where idnumber not in (select id from table where id <=1000000)