2009-06-29 5 views
30

J'ai une colonne nommée sequence. Les données dans cette colonne ressemble à 1, 2, 3, 4, 5, 7, 9, 10, 15.Requête SQL pour trouver les numéros de séquence manquants

J'ai besoin de trouver les numéros de séquence manquants dans le tableau. Quelle requête SQL trouvera les numéros de séquence manquants de ma table? J'attends des résultats comme

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

J'utilise une seule table. J'ai essayé la requête ci-dessous, mais je n'obtiens pas les résultats que je veux.

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! C'est une question en double. – Anvesh

+0

Veuillez l'utiliser pour référence. http://stackoverflow.com/questions/1389605/sql-find-missing-ids-in-a-table – Anvesh

Répondre

6

Essayez avec ceci:

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

Cette solution est claire et fonctionne parfaitement. – Waldhorn

22

Que diriez-vous quelque chose comme:

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) 

récapitulant les résultats:

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

Semble plus simple que le mien, et n'utilise pas une table temporaire ... Je vais enregistrer ce bout de code et l'essayer. – Jonathan

+0

c'est assez inefficace ... voir la réponse de jointure à gauche –

+0

Une autre version: http://sqlfiddle.com/#!4/62fb0/2/0 – SNathan

-1

Il y a une discussion de SQL pour résoudre ce genre du problème au http://www.duelec.de/blog/?p=337.

Il n'est pas écrit spécifiquement dans sqlserver2005 mais il devrait vous donner assez d'informations pour que vous puissiez l'adapter.

+0

Ce blog est protégé par mot de passe maintenant. – user323094

+0

lien ne peut pas être consulté – newshorts

+0

répondeur et commentateurs, J'espère que ce lien d'archives aide: http://web.archive.org/web/20090328170226/http://www.duelec.de/blog/?p=337 –

0

Vous pouvez également résoudre en utilisant quelque chose comme un CTE pour générer la séquence complète:

 
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 mise en forme ne fonctionne pas ici pour une raison quelconque? Quelqu'un peut-il voir le problème?

+0

Bon essai , mais: "SELECT 1" doit être remplacé par "SELECT MIN (...)". Et si vous avez plus de 100 éléments, la récursivité ne fonctionnera pas. – van

0

Les solutions ne sont-elles pas toutes trop complexes? serait-ce pas beaucoup plus simple:

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

j'ai 50000 enregistrements ... comment puis-je sélectionner puis –

+0

cela semble intéressant, la chose qui m'inquiète est la performance et l'utilisation de spt_values ​​... –

+1

Que faire si sa table a plus de lignes (ou plus le numéro de séquence), puis le nombre de lignes dans la table "spt_values"? – van

10

Les meilleures solutions sont celles qui utilisent une table temporaire avec la séquence. En supposant que vous construisez une telle table, LEFT JOIN avec contrôle NULL devrait faire le travail:

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

Mais si vous devez répéter cette opération souvent (et plus de pour 1 séquence dans la base de données), je voudrais créer un " static-data "table et avoir un script pour le remplir à la MAX (valeur) de toutes les tables dont vous avez besoin.

+0

+1 J'allais juste écrire cela –

+1

Voir: http://www.projectdmx.com/tsql/tblnumbers.aspx sur la façon de créer des tables de séquence –

+0

@van, n'hésitez pas à ajouter un lien qui explique comment créer la séquence table, il rendra la réponse plus complète. –

15

Je sais que c'est un très ancien poste mais je voulais ajouter cette solution que j'ai trouvé HERE pour que je puisse trouver plus facilement:

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

En MySql en utilisant votre ligne commentée au lieu de lancer cette option travaillé pour moi. Je vous remercie. – jessier3

2

Voici un script pour créer une procédure stockée qui renvoie des numéros séquentiels manquants pour une plage de dates donnée.

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

C'est une solution qui fonctionne parfaitement pour moi. –

1

Ceci est mon interprétation de cette question, en plaçant le contenu dans une variable de table que je peux facilement accéder dans le reste de mon 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

Juste pour le plaisir, j'ai décidé de poster ma solution.
J'avais une colonne d'identité dans ma table et je voulais trouver les numéros de facture manquants. J'ai passé en revue tous les exemples que j'ai pu trouver mais ils n'étaient pas assez élégants.

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 

Je trouve cette réponse ici: http://sql-developers.blogspot.com/2012/10/how-to-find-missing-identitysequence.html

Je cherchais une solution et a trouvé beaucoup de réponses. C'est celui que j'ai utilisé et ça a très bien marché. J'espère que cela aidera tous ceux qui cherchent une réponse similaire.

0

Créer une Tally table utile:

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

Index, ou faire que la première colonne PK. Ensuite, utilisez EXCEPT pour obtenir votre numéro manquant.

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