查找序列中的缺失值
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
【讨论】:
如果跳过了多个序列号将不起作用。以上是关于查找序列中的缺失值的主要内容,如果未能解决你的问题,请参考以下文章