2009-06-29 37 views
30

Ho una colonna denominata sequence. I dati in questa colonna sono 1, 2, 3, 4, 5, 7, 9, 10, 15.Query SQL per trovare i numeri di sequenza mancanti

Ho bisogno di trovare i numeri di sequenza mancanti dalla tabella. Quale query SQL troverà i numeri di sequenza mancanti dalla mia tabella? Mi aspetto risultati come

Missing numbers 
--------------- 
6 
8 
11 
12 
13 
14 

Sto usando solo una tabella. Ho provato la query qui sotto, ma non sto ottenendo i risultati che voglio.

select de.sequence + 1 as sequence from dataentry as de 
left outer join dataentry as de1 on de.sequence + 1 = de1.sequence 
where de1.sequence is null order by sequence asc; 
+0

Hey! Questa è una domanda doppia. – Anvesh

+0

Si prega di utilizzare questo per riferimento. http://stackoverflow.com/questions/1389605/sql-find-missing-ids-in-a-table – Anvesh

risposta

6

prova con questo:

declare @min int 
declare @max int 

select @min = min(seq_field), @max = max(seq_field) from [Table] 

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

Questa soluzione è chiara e funziona perfettamente. – Waldhorn

22

ne dite qualcosa di simile:

select (select isnull(max(val)+1,1) from mydata where val < md.val) as [from], 
    md.val - 1 as [to] 
    from mydata md 
    where md.val != 1 and not exists (
     select 1 from mydata md2 where md2.val = md.val - 1) 

dando risultati riassunti:

from  to 
----------- ----------- 
6   6 
8   8 
11   14 
+0

Sembra più semplice del mio e non usa una tabella temporanea ... Salverò questo frammento di codice e provalo. – Jonathan

+0

questo è piuttosto inefficiente ... vedere la risposta basata su join sinistro –

+0

Un'altra versione: http://sqlfiddle.com/#!4/62fb0/2/0 – SNathan

-1

C'è una discussione di SQL per risolvere questo tipo di problema a http://www.duelec.de/blog/?p=337.

Non è scritto specificamente in sqlserver2005 ma dovrebbe darti abbastanza informazioni per adattarlo.

+0

Questo blog è protetto da password ora. – user323094

+0

collegamento non accessibile – newshorts

+0

risponditore e commentatore, spero che questo collegamento all'archivio aiuti: http://web.archive.org/web/20090328170226/http://www.duelec.de/blog/?p=337 –

0

Si potrebbe anche risolvere usando qualcosa come un CTE per generare la sequenza completa:

 
create table #tmp(sequence int) 

insert into #tmp(sequence) values (1) 
insert into #tmp(sequence) values (2) 
insert into #tmp(sequence) values (3) 
insert into #tmp(sequence) values (5) 
insert into #tmp(sequence) values (6) 
insert into #tmp(sequence) values (8) 
insert into #tmp(sequence) values (10) 
insert into #tmp(sequence) values (11) 
insert into #tmp(sequence) values (14) 

DECLARE @max INT 
    SELECT @max = max(sequence) from #tmp; 

    with full_sequence 
    (
     Sequence 
    ) 
    as 
    (
     SELECT 1 Sequence 

     UNION ALL 

     SELECT Sequence + 1 
     FROM full_sequence 
     WHERE Sequence < @max 
    ) 

    SELECT 
     full_sequence.sequence 
    FROM 
     full_sequence 
    LEFT JOIN 
     #tmp 
    ON 
     full_sequence.sequence = #tmp.sequence 
    WHERE 
     #tmp.sequence IS NULL 

Hmmmm - la formattazione non sta lavorando a qui per qualche motivo? Qualcuno può vedere il problema?

+0

Buona prova , ma: "SELECT 1" deve essere sostituito con "SELECT MIN (...)". E se hai più di 100 articoli, la ricorsione non funzionerà. – van

0

Le soluzioni fornite non sono tutte troppo complesse? Non sarebbe molto più semplice:

SELECT * 
FROM (SELECT row_number() over(order by number) as N from master..spt_values) t 
where N not in (select 1 as sequence union 
     select 2 union 
     select 3 union 
     select 4 union 
     select 5 union 
     select 7 union 
     select 10 union 
     select 15 
     ) 
+0

ho 50000 record..come faccio a selezionare poi –

+0

questo sembra interessante, la cosa che mi preoccuperebbe è la prestazione e l'uso di spt_values ​​... –

+1

E se la sua tabella ha più righe (o numero di sequenza più alto) quindi numero di righe nella tabella "spt_values"? – van

10

Le soluzioni migliori sono quelli che utilizzano una tabella temporanea con la sequenza. Supponendo che si costruisce una tale tabella, LEFT JOIN con assegno NULL dovrebbe fare il lavoro:

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

Ma se si deve ripetere l'operazione spesso (e più poi per 1 sequenza nella banca dati), vorrei creare un " tabella di dati statici "e avere uno script per popolarlo al valore MAX (valore) di tutte le tabelle necessarie.

+0

+1 Stavo per scrivere quello –

+1

Vedere: http://www.projectdmx.com/tsql/tblnumbers.aspx su come creare tabelle di sequenze –

+0

@van, sentiti libero di aggiungere un link che spiega come creare la sequenza tavolo renderà la risposta più completa. –

15

So che questo è un post molto vecchio, ma ho voluto aggiungere questa soluzione che ho trovato HERE in modo che riesco a trovare più facile:

WITH Missing (missnum, maxid) 
AS 
(
SELECT 1 AS missnum, (select max(id) from @TT) 
UNION ALL 
SELECT missnum + 1, maxid FROM Missing 
WHERE missnum < maxid 
) 
SELECT missnum 
FROM Missing 
LEFT OUTER JOIN @TT tt on tt.id = Missing.missnum 
WHERE tt.id is NULL 
OPTION (MAXRECURSION 0); 
0
DECLARE @TempSujith TABLE 
(MissingId int) 

Declare @Id Int 
DECLARE @mycur CURSOR 
SET @mycur = CURSOR FOR Select Id From tbl_Table 

OPEN @mycur 

FETCH NEXT FROM @mycur INTO @Id 
Declare @index int 
Set @index = 1 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    if (@index < @Id) 
    begin 
     while @index < @Id 
     begin 
      insert into @TempSujith values (@index) 
      set @index = @index + 1 
     end 
    end 
    set @index = @index + 1 
FETCH NEXT FROM @mycur INTO @Id 
END 
Select Id from tbl_Table 
select MissingId from @TempSujith 
1
SELECT CASE WHEN MAX(column_name) = COUNT(*) 
THEN CAST(NULL AS INTEGER) 
-- THEN MAX(column_name) + 1 as other option 
WHEN MIN(column_name) > 1 
THEN 1 
WHEN MAX(column_name) <> COUNT(*) 
THEN (SELECT MIN(column_name)+1 
FROM table_name 
WHERE (column_name+ 1) 
NOT IN (SELECT column_name FROM table_name)) 
ELSE NULL END 
FROM table_name; 
+0

In MySql usando la tua linea commentata invece di lanciare questa opzione ha funzionato per me Grazie. – jessier3

2

Ecco uno script per creare una stored procedure che restituisce numeri sequenziali mancanti per un determinato intervallo di date.

CREATE PROCEDURE dbo.ddc_RolledBackOrders 
-- Add the parameters for the stored procedure here 
@StartDate DATETIME , 
@EndDate DATETIME 
AS 
    BEGIN 

    SET NOCOUNT ON; 

    DECLARE @Min BIGINT 
    DECLARE @Max BIGINT 
    DECLARE @i BIGINT 

    IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL 
     BEGIN 
      DROP TABLE #TempTable 
     END 

    CREATE TABLE #TempTable 
     (
      TempOrderNumber BIGINT 
     ) 

    SELECT @Min = (SELECT MIN(ordernumber) 
        FROM dbo.Orders WITH (NOLOCK) 
        WHERE OrderDate BETWEEN @StartDate AND @EndDate) 
    SELECT @Max = (SELECT MAX(ordernumber) 
        FROM dbo.Orders WITH (NOLOCK) 
        WHERE OrderDate BETWEEN @StartDate AND @EndDate) 
    SELECT @i = @Min 

    WHILE @i <= @Max 
     BEGIN 
      INSERT INTO #TempTable 
        SELECT @i 

      SELECT @i = @i + 1 

     END 

    SELECT TempOrderNumber 
    FROM #TempTable 
      LEFT JOIN dbo.orders o WITH (NOLOCK) ON tempordernumber = o.OrderNumber 
    WHERE o.OrderNumber IS NULL 

END 

GO

+0

Questa è la soluzione perfetta per me. –

1

Questa è la mia interpretazione di questo problema, mettendo il contenuto in una variabile tabella che facilmente può accedere nel resto del mio script.

DECLARE @IDS TABLE (row int, ID int) 

INSERT INTO @IDS 
select  ROW_NUMBER() OVER (ORDER BY x.[Referred_ID]), x.[Referred_ID] FROM 
(SELECT  b.[Referred_ID] + 1 [Referred_ID] 
FROM  [catalog].[dbo].[Referrals] b) as x 
LEFT JOIN [catalog].[dbo].[Referrals] a ON x.[Referred_ID] = a.[Referred_ID] 
WHERE  a.[Referred_ID] IS NULL 

select * from @IDS 
1

Solo per divertimento, ho deciso di pubblicare la mia soluzione.
Avevo una colonna di identità nella mia tabella e volevo trovare numeri di fattura mancanti. Ho rivisto tutti gli esempi che ho trovato ma non erano abbastanza eleganti.

CREATE VIEW EENSkippedInvoicveNo 
AS 

SELECT CASE WHEN MSCNT = 1 THEN CAST(MSFIRST AS VARCHAR (8)) ELSE 
    CAST(MSFIRST AS VARCHAR (8)) + ' - ' + CAST(MSlAST AS VARCHAR (8)) END AS MISSING, 
MSCNT, INV_DT FROM ( 
select invNo+1 as Msfirst, inv_no -1 as Mslast, inv_no - invno -1 as msCnt, dbo.fmtdt(Inv_dt) AS INV_dT 
from (select inv_no as invNo, a4glidentity + 1 as a4glid 
from oehdrhst_sql where inv_dt > 20140401) as s 
inner Join oehdrhst_sql as h 
on a4glid = a4glidentity 
where inv_no - invno <> 1 
) AS SS 
1
DECLARE @MaxID INT = (SELECT MAX(timerecordid) FROM dbo.TimeRecord) 

SELECT SeqID AS MissingSeqID 
FROM (SELECT ROW_NUMBER() OVER (ORDER BY column_id) SeqID from sys.columns) LkUp 
LEFT JOIN dbo.TimeRecord t ON t.timeRecordId = LkUp.SeqID 
WHERE t.timeRecordId is null and SeqID < @MaxID 

ho trovato questa risposta qui: http://sql-developers.blogspot.com/2012/10/how-to-find-missing-identitysequence.html

ero alla ricerca di una soluzione e hanno trovato molte risposte. Questo è quello che ho usato e ha funzionato molto bene. Spero che questo aiuti chiunque cerchi una risposta simile.

0

Creare un utile Tally table:

-- can go up to 4 million or 2^22 
select top 100000 identity(int, 1, 1) Id 
into Tally 
from master..spt_values 
cross join master..spt_values 

Indice di esso, o fare quella singola colonna come PK. Quindi utilizzare TRANNE per ottenere il numero mancante.

select Id from Tally where Id <= (select max(Id) from TestTable) 
except 
select Id from TestTable 
0
-- This will return better Results 
    -- ---------------------------------- 
    ;With CTERange 
    As (
    select (select isnull(max(ArchiveID)+1,1) from tblArchives where ArchiveID < md.ArchiveID) as [from], 
     md.ArchiveID - 1 as [to] 
     from tblArchives md 
     where md.ArchiveID != 1 and not exists (
      select 1 from tblArchives md2 where md2.ArchiveID = md.ArchiveID - 1) 
    ) SELECT [from], [to], ([to]-[from])+1 [total missing] 
    From CTERange 
    ORDER BY ([to]-[from])+1 DESC; 


from  to  total missing 
------- ------- -------------- 
6  6  1 
8  8  1 
11  14  4 
Problemi correlati