SQL-запрос для поиска отсутствующих порядковых номеров - PullRequest
37 голосов
/ 29 июня 2009

У меня есть столбец с именем sequence. Данные в этом столбце выглядят как 1, 2, 3, 4, 5, 7, 9, 10, 15.

Мне нужно найти пропущенные порядковые номера из таблицы. Какой запрос SQL найдет недостающие порядковые номера из моей таблицы? Я ожидаю результатов, таких как

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

Я использую только одну таблицу. Я попробовал запрос ниже, но не получил желаемых результатов.

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;

Ответы [ 14 ]

25 голосов
/ 29 июня 2009

Как насчет чего-то вроде:

  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)

дает обобщенные результаты:

from        to
----------- -----------
6           6
8           8
11          14
18 голосов
/ 10 декабря 2011

Я знаю, что это очень старый пост, но я хотел добавить решение, которое нашел ЗДЕСЬ , чтобы мне было проще его найти:

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); 
12 голосов
/ 29 июня 2009

Попробуйте с этим:

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
10 голосов
/ 29 июня 2009

Лучшие решения - это те, которые используют временную таблицу с последовательностью. Предполагая, что вы создаете такую ​​таблицу, LEFT JOIN с проверкой NULL должны выполнить работу:

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

Но если вам придется часто повторять эту операцию (и более чем для 1 последовательности в базе данных), я бы создал таблицу «static-data» и имел бы скрипт, чтобы заполнить ее значением MAX (значением) всех столы вам нужны.

2 голосов
/ 01 февраля 2013

Вот скрипт для создания хранимой процедуры, которая возвращает отсутствующие порядковые номера для заданного диапазона дат.

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

2 голосов
/ 22 февраля 2012
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;
1 голос
/ 13 декабря 2017
 -- 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
1 голос
/ 27 мая 2014
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

Я нашел этот ответ здесь: http://sql -developers.blogspot.com / 2012/10 / как к найти пропущенное-identitysequence.html

Я искал решение и нашел много ответов. Это тот, который я использовал, и он работал очень хорошо. Я надеюсь, что это поможет любому, кто ищет подобный ответ.

1 голос
/ 22 апреля 2014

Ради интереса я решил опубликовать свое решение.
В моей таблице был столбец идентификаторов, и я хотел найти пропущенные номера счетов. Я просмотрел все примеры, которые смог найти, но они не были достаточно элегантными.

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 голос
/ 02 апреля 2014

Это моя интерпретация этой проблемы, помещающая содержимое в переменную таблицы, к которой я могу легко получить доступ в оставшейся части моего скрипта.

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