【问题标题】:finding the missing values in a Sequence查找序列中的缺失值
【发布时间】:2026-01-26 12:45:02
【问题描述】:

表1如下:

Col1
1
2
3
4
6
7
8
9
10
13
14

如上所示,col1 具有值序列,但由于某种原因,用户没有插入 5、11 等。如何找出序列中的缺失值。这里的序列是 1 到 14,缺失值是 5,11。请帮帮我。

【问题讨论】:

  • 如果您发布代码、XML 或数据示例,在文本编辑器中突出显示这些行,然后单击编辑器上的“代码示例”按钮 ({ })工具栏以很好地格式化和语法突出显示它!

标签: sql-server-2005


【解决方案1】:

正如在其他答案中所说,最好的选择是使用真实的序列表进行连接。您可以使用递归 CTE 创建一个:

DECLARE @MaxNumber INT
SELECT @MaxNumber = MAX(Col1) FROM YourTable;

WITH CTE AS
(
    SELECT 1 Col1
    UNION ALL
    SELECT Col1+1
    FROM CTE 
    WHERE Col1+1 <= @MaxNumber
)
SELECT A.Col1
FROM CTE A
LEFT JOIN YourTable B
ON A.Col1 = B.Col1
WHERE B.Col1 IS NULL
OPTION(MAXRECURSION 0)

【讨论】:

    【解决方案2】:

    这适用于 0 - 2000 的大数字,您只需交叉加入原始结果集即可。

    with temp as (
      select distinct number
    from master..spt_Values
    where number between 0 and 2000
    )
    
    select * from
    temp t
    left join your_table y on y.col1 = t.number
    where y.col1 is null 
    

    或者使用交叉连接

    这对数十亿人的工作速度显然要慢

        WITH
          L0   AS(SELECT 1 AS c UNION ALL SELECT 1),
          L1   AS(SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B),
          L2   AS(SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B),
          L3   AS(SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B),
          L4   AS(SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B),
          L5   AS(SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B),
          Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5)
    
      select * from
        l5 t
        left join your_table y on y.col1 = t.n
        where y.col1 is null 
    

    【讨论】:

      【解决方案3】:

      这似乎是重复

      SQL query to find Missing sequence numbers

      有一个可行的建议:

      SELECT      l.id + 1 as start
      FROM        Table1 as l
      LEFT JOIN   Table1 as r on l.id + 1 = r.id
      WHERE       r.id IS NULL
      

      否则,您可以使用序列表在您的表上留下连接。从上面的问题,你可以看看http://www.projectdmx.com/tsql/tblnumbers.aspx,了解如何生成合适的序列表,join 会是这样的

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

      【讨论】:

        【解决方案4】:

        旁注对所有递归 CTE 建议。递归 CTE 增加时间与行数成线性关系。使用计数表或交叉连接要好得多...

        这可行:

        -- data table
        CREATE TABLE #data (
            value INT
        )
        
        INSERT #data VALUES (1)
        INSERT #data VALUES (2)
        INSERT #data VALUES (3)
        INSERT #data VALUES (4)
        INSERT #data VALUES (6)
        INSERT #data VALUES (7)
        INSERT #data VALUES (8)
        INSERT #data VALUES (9)
        INSERT #data VALUES (10)
        INSERT #data VALUES (13)
        INSERT #data VALUES (14)
        
        -- normally i have a tally table already for stuff like this but I'll
        -- create one temporary here.
        CREATE TABLE #tmp_tally (
            n INT
        )
        
        DECLARE @n INT
        SET @n = 1
        WHILE @n < 14
        BEGIN
            INSERT #tmp_tally VALUES (@n)
            SET @n = @n + 1
        END
        
        SELECT
            T.n,
            CASE WHEN #data.value IS NULL THEN 'Missing' ELSE 'Not Missing' END
        FROM
            #tmp_tally T
            LEFT JOIN #data ON
            T.n = #data.value
        WHERE
            T.n <= (SELECT MAX(value) FROM #data) -- max of what you want to check against which is 14 in your example
        
        DROP TABLE #data
        DROP TABLE #tmp_tally
        

        【讨论】:

        • 请称它为数字表。它不是在“统计”任何东西! :-)
        • tally 没什么问题...这意味着在计数表中计数。它也是它的通用名称,因此含义实际上无关紧要。
        【解决方案5】:

        试试这个:

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

        使用上述脚本,您将从#tmp 表的“ID”列中获取缺失值。

        希望对你有帮助!!

        【讨论】:

          【解决方案6】:

          我会在同一个表中做一个子查询,看看当前数字 1 是否存在另一个数字,如果不存在,你就知道跳过了一个数字。您也可以为此 +1。

          选择 nt.numb, 案子 (select COUNT(*) from table where numb=nt.numb-1)=0 THEN 'skipped' ELSE 'not skipped' 从 数表nt

          【讨论】:

          • 如果跳过了多个序列号将不起作用。