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.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Venkateswarlu Avula
  • 341
  • 1
  • 4
  • 14
  • 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! – marc_s Feb 17 '12 at 12:25
  • possible duplicate of [SQL query to find Missing sequence numbers](http://stackoverflow.com/questions/1057389/sql-query-to-find-missing-sequence-numbers) – juergen d Feb 17 '12 at 12:36

6 Answers6

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)
Lamak
  • 69,480
  • 12
  • 108
  • 116
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 
JStead
  • 1,710
  • 11
  • 12
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!!

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
Community
  • 1
  • 1
James Osborn
  • 1,275
  • 7
  • 12
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
Asken
  • 7,679
  • 10
  • 45
  • 77
-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

Aklopper
  • 56
  • 4