Sql server 2005 SQL查询以查找缺少的序列号

Sql server 2005 SQL查询以查找缺少的序列号,sql-server-2005,gaps-and-islands,Sql Server 2005,Gaps And Islands,我有一个名为sequence的列。此列中的数据看起来像1、2、3、4、5、7、9、10、15 我需要从表中找到缺失的序列号。什么SQL查询将从我的表中查找缺少的序列号?我期待这样的结果 Missing numbers --------------- 6 8 11 12 13 14 我只用一张桌子。我尝试了下面的查询,但没有得到我想要的结果 select de.sequence + 1 as sequence from dataentry as de left oute

我有一个名为sequence的列。此列中的数据看起来像1、2、3、4、5、7、9、10、15

我需要从表中找到缺失的序列号。什么SQL查询将从我的表中查找缺少的序列号?我期待这样的结果

Missing numbers
---------------
6  
8  
11  
12  
13  
14  
我只用一张桌子。我尝试了下面的查询,但没有得到我想要的结果

select de.sequence + 1 as sequence from dataentry as de 
left outer join dataentry as de1 on de.sequence + 1 = de1.sequence
where de1.sequence is null  order by sequence asc;
试试这个:

declare @min int
declare @max int

select @min = min(seq_field), @max = max(seq_field) from [Table]

create table #tmp (Field_No int)
while @min <= @max
begin
   if not exists (select * from [Table] where seq_field = @min)
      insert into #tmp (Field_No) values (@min)
   set @min = @min + 1
end
select * from #tmp
drop table #tmp

比如说:

  select (select isnull(max(val)+1,1) from mydata where val < md.val) as [from],
     md.val - 1 as [to]
  from mydata md
  where md.val != 1 and not exists (
        select 1 from mydata md2 where md2.val = md.val - 1)

您还可以使用CTE之类的工具来生成完整序列:

create table #tmp(sequence int) insert into #tmp(sequence) values (1) insert into #tmp(sequence) values (2) insert into #tmp(sequence) values (3) insert into #tmp(sequence) values (5) insert into #tmp(sequence) values (6) insert into #tmp(sequence) values (8) insert into #tmp(sequence) values (10) insert into #tmp(sequence) values (11) insert into #tmp(sequence) values (14)
Hmmmm-出于某种原因,这里的格式设置不起作用?有人能看到这个问题吗?

给出的解决方案不是都太复杂了吗? 这不是更简单吗:

SELECT  *
FROM    (SELECT  row_number() over(order by number) as N from master..spt_values) t
where   N not in (select 1 as sequence union  
        select 2 union 
        select 3 union 
        select 4 union 
        select 5 union 
        select 7 union 
        select 10 union 
        select 15
        )

最好的解决方案是使用带有序列的临时表。假设您构建了这样一个表,使用NULL check的LEFT JOIN应该完成以下工作:

SELECT      #sequence.value
FROM        #sequence
LEFT JOIN   MyTable ON #sequence.value = MyTable.value
WHERE       MyTable.value IS NULL

但是,如果您必须经常重复此操作,并且多次重复数据库中的1个序列,我将创建一个静态数据表,并使用脚本将其填充到您需要的所有表的最大值。

我知道这是一篇非常古老的文章,但我想添加我发现的此解决方案,以便更轻松地找到它:

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); 

下面是一个脚本,用于创建一个存储过程,该过程返回给定日期范围内丢失的序列号

CREATE PROCEDURE dbo.ddc_RolledBackOrders 
-- Add the parameters for the stored procedure here
@StartDate DATETIME ,
@EndDate DATETIME
AS 
    BEGIN

    SET NOCOUNT ON;

    DECLARE @Min BIGINT
    DECLARE @Max BIGINT
    DECLARE @i BIGINT

    IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL 
        BEGIN
            DROP TABLE #TempTable
        END

    CREATE TABLE #TempTable
        (
          TempOrderNumber BIGINT
        )

    SELECT  @Min = ( SELECT MIN(ordernumber)
                     FROM   dbo.Orders WITH ( NOLOCK )
                     WHERE OrderDate BETWEEN @StartDate AND @EndDate)
    SELECT  @Max = ( SELECT MAX(ordernumber)
                     FROM   dbo.Orders WITH ( NOLOCK )
                     WHERE OrderDate BETWEEN @StartDate AND @EndDate)
    SELECT  @i = @Min

    WHILE @i <= @Max 
        BEGIN
            INSERT  INTO #TempTable
                    SELECT  @i

            SELECT  @i = @i + 1

        END

    SELECT  TempOrderNumber
    FROM    #TempTable
            LEFT JOIN dbo.orders o WITH ( NOLOCK ) ON tempordernumber = o.OrderNumber
    WHERE   o.OrderNumber IS NULL

END

GO

这是我对这个问题的解释,将内容放在一个表变量中,我可以在脚本的其余部分轻松访问该变量

DECLARE @IDS TABLE (row int, ID int)

INSERT INTO @IDS
select      ROW_NUMBER() OVER (ORDER BY x.[Referred_ID]), x.[Referred_ID] FROM
(SELECT      b.[Referred_ID] + 1 [Referred_ID]
FROM        [catalog].[dbo].[Referrals] b) as x
LEFT JOIN   [catalog].[dbo].[Referrals] a ON x.[Referred_ID] = a.[Referred_ID]
WHERE       a.[Referred_ID] IS NULL

select * from @IDS

只是为了好玩,我决定发布我的解决方案。 我的表中有一个标识列,我想找到丢失的发票号。 我回顾了我能找到的所有例子,但它们不够优雅

CREATE VIEW EENSkippedInvoicveNo
AS

SELECT CASE WHEN MSCNT = 1 THEN CAST(MSFIRST AS VARCHAR (8)) ELSE
    CAST(MSFIRST AS VARCHAR (8)) + ' - ' + CAST(MSlAST AS VARCHAR (8))  END AS MISSING,
MSCNT, INV_DT  FROM ( 
select  invNo+1  as Msfirst, inv_no -1 as Mslast, inv_no - invno -1 as msCnt, dbo.fmtdt(Inv_dt)  AS INV_dT
from (select inv_no as invNo,  a4glidentity + 1  as a4glid 
from oehdrhst_sql where inv_dt > 20140401) as s
inner Join oehdrhst_sql as h
on a4glid = a4glidentity 
where inv_no - invno <> 1
) AS SS
我在这里找到了答案:

我在寻找解决方案,并找到了许多答案。这是我用过的,效果很好。我希望这能帮助寻找类似答案的人。

创建一个有用的:

索引它,或者将单个列作为PK。 然后使用EXCEPT获取丢失的号码

select Id from Tally where Id <= (select max(Id) from TestTable)
except
select Id from TestTable
正在为我的公司开发一个客户号码生成器。不是最有效的,但绝对是最可读的

该表有一个Id列。 该表允许用户按关闭顺序手动插入ID。
该解决方案解决了这样一种情况:用户决定选择一个比我简单的高数值,并且不使用临时表。。。我将保存这段代码并尝试它。这是非常低效的。。。请参阅左侧基于联接的回答Good try,但是:SELECT 1应替换为SELECT MIN。。。。如果你有超过100个项目,递归将不起作用。我有50000条记录。我该如何选择呢?这看起来很有趣,我担心的是性能和spt_值的使用……如果他的表有更多的行或更高的序列号,那么spt_值表中的行数会怎么样?您可以轻松地对表进行交叉连接以获得更多的行。通常,数据库中有一个数字表,该表已编制索引,速度很快。请参阅:关于如何创建序列tables@SamSaffron林克死了。这是Wayback机器的缓存副本:请使用它作为参考。这回答了你的问题吗?在MySql中,使用注释掉的行而不是强制转换这个选项对我很有效。非常感谢。
CREATE PROCEDURE dbo.ddc_RolledBackOrders 
-- Add the parameters for the stored procedure here
@StartDate DATETIME ,
@EndDate DATETIME
AS 
    BEGIN

    SET NOCOUNT ON;

    DECLARE @Min BIGINT
    DECLARE @Max BIGINT
    DECLARE @i BIGINT

    IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL 
        BEGIN
            DROP TABLE #TempTable
        END

    CREATE TABLE #TempTable
        (
          TempOrderNumber BIGINT
        )

    SELECT  @Min = ( SELECT MIN(ordernumber)
                     FROM   dbo.Orders WITH ( NOLOCK )
                     WHERE OrderDate BETWEEN @StartDate AND @EndDate)
    SELECT  @Max = ( SELECT MAX(ordernumber)
                     FROM   dbo.Orders WITH ( NOLOCK )
                     WHERE OrderDate BETWEEN @StartDate AND @EndDate)
    SELECT  @i = @Min

    WHILE @i <= @Max 
        BEGIN
            INSERT  INTO #TempTable
                    SELECT  @i

            SELECT  @i = @i + 1

        END

    SELECT  TempOrderNumber
    FROM    #TempTable
            LEFT JOIN dbo.orders o WITH ( NOLOCK ) ON tempordernumber = o.OrderNumber
    WHERE   o.OrderNumber IS NULL

END
DECLARE @IDS TABLE (row int, ID int)

INSERT INTO @IDS
select      ROW_NUMBER() OVER (ORDER BY x.[Referred_ID]), x.[Referred_ID] FROM
(SELECT      b.[Referred_ID] + 1 [Referred_ID]
FROM        [catalog].[dbo].[Referrals] b) as x
LEFT JOIN   [catalog].[dbo].[Referrals] a ON x.[Referred_ID] = a.[Referred_ID]
WHERE       a.[Referred_ID] IS NULL

select * from @IDS
CREATE VIEW EENSkippedInvoicveNo
AS

SELECT CASE WHEN MSCNT = 1 THEN CAST(MSFIRST AS VARCHAR (8)) ELSE
    CAST(MSFIRST AS VARCHAR (8)) + ' - ' + CAST(MSlAST AS VARCHAR (8))  END AS MISSING,
MSCNT, INV_DT  FROM ( 
select  invNo+1  as Msfirst, inv_no -1 as Mslast, inv_no - invno -1 as msCnt, dbo.fmtdt(Inv_dt)  AS INV_dT
from (select inv_no as invNo,  a4glidentity + 1  as a4glid 
from oehdrhst_sql where inv_dt > 20140401) as s
inner Join oehdrhst_sql as h
on a4glid = a4glidentity 
where inv_no - invno <> 1
) AS SS
DECLARE @MaxID INT = (SELECT MAX(timerecordid) FROM dbo.TimeRecord)

SELECT SeqID AS MissingSeqID
FROM (SELECT ROW_NUMBER() OVER (ORDER BY column_id) SeqID from sys.columns) LkUp
LEFT JOIN dbo.TimeRecord t ON t.timeRecordId = LkUp.SeqID
WHERE t.timeRecordId is null and SeqID < @MaxID
-- can go up to 4 million or 2^22
select top 100000 identity(int, 1, 1) Id
into Tally
from master..spt_values
cross join master..spt_values
select Id from Tally where Id <= (select max(Id) from TestTable)
except
select Id from TestTable
 -- This will return better Results
    -- ----------------------------------
    ;With CTERange
    As (
    select (select isnull(max(ArchiveID)+1,1) from tblArchives where ArchiveID < md.ArchiveID) as [from],
         md.ArchiveID - 1 as [to]
      from tblArchives md
      where md.ArchiveID != 1 and not exists (
            select 1 from tblArchives md2 where md2.ArchiveID = md.ArchiveID - 1)
    ) SELECT [from], [to], ([to]-[from])+1 [total missing]
    From CTERange 
    ORDER BY ([to]-[from])+1 DESC;


from     to     total missing
------- ------- --------------
6        6      1 
8        8      1
11       14     4
SELECT TOP 1 (Id + 1)
FROM CustomerNumberGenerator
WHERE (Id + 1) NOT IN ( SELECT Id FROM CustomerNumberGenerator )