查找序列中的缺失值

Posted

技术标签:

【中文标题】查找序列中的缺失值【英文标题】:finding the missing values in a Sequence 【发布时间】:2012-02-17 12:24:38 【问题描述】:

表1如下:

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

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

【问题讨论】:

如果您发布代码、XML 或数据示例,在文本编辑器中突出显示这些行,然后单击编辑器上的“代码示例”按钮 ( )工具栏以很好地格式化和语法突出显示它! SQL query to find Missing sequence numbers 的可能重复项 【参考方案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

【讨论】:

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

以上是关于查找序列中的缺失值的主要内容,如果未能解决你的问题,请参考以下文章

如何检查时间序列数据(月度数据)的缺失值?

用序列中的缺失值替换 NA (R)

用于异常检测的具有缺失值的时间序列的 STL 分解

数据分析缺失值处理(Missing Values)——删除法填充法插值法

删除缺失值的插值时间序列图

在 dtype obj 的 NumPy 数组中查找缺失值