0

Table1 is as follows :

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

As shown above the col1 has the sequence of values but for some reason the user did not insert 5, 11 and so on. How to find out the missing values in a sequence. Here the sequence is 1 to 14 and the missing values are 5,11. Please help me.

2
  • 1
    If you post code, XML or data samples, PLEASE highlight those lines in the text editor and click on the "code samples" button ( { } ) on the editor toolbar to nicely format and syntax highlight it! Commented Feb 17, 2012 at 12:25
  • possible duplicate of SQL query to find Missing sequence numbers Commented Feb 17, 2012 at 12:36

6 Answers 6

4

As was said in other answers, the best choice is to do a join with a real sequence table. You can create one using a recursive 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)
Sign up to request clarification or add additional context in comments.

Comments

3

This will work for numbers 0 - 2000 for large numbers you just need to cross join the original result set.

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 

alternatively using cross join

This will work for billions obviously slower

    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 

Comments

0

This seems to pretty much be a duplication of

SQL query to find Missing sequence numbers

There's a suggestions this will work:

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

Otherwise you can left join on your table with a sequence table. From the above question, you can look at http://www.projectdmx.com/tsql/tblnumbers.aspx to get some ideas on how to generate a suitable sequence table, and the join will be something like

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

Comments

0

Side-note to all recursive CTE suggestions. The recursive CTE increases time linear to the number of rows. Using a tally table or cross-join is much better to use...

This would work:

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

2 Comments

Just please call it a numbers table. It is not "tallying" anything! :-)
Nothing wrong with tally... it means count in tally-table. It's also the common name for it so the meaning is actually irrelevant.
0

Try this:

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

With the above script you will get missing values in "ID" column from #tmp table.

Hope this will help you!!

Comments

-1

I would do a subquery in the same table, to see if another number exist for the current number-1, and if there is not one, you know that a number was skipped. You can do the +1 of this as well.

select nt.numb, CASE (select COUNT(*) from table where numb=nt.numb-1)=0 THEN 'skipped' ELSE 'not skipped' from numbertable nt

1 Comment

Won't work if there is more than one sequential number skipped.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.