Справка по SQL-запросам - Отрицательные отчеты - PullRequest
0 голосов
/ 01 июня 2018

Возможно, кто-то может помочь с Идеями или Решением.Пользователь попросил у меня отрицательный отзыв.У нас есть таблица с билетами, у каждого билета есть номер билета, который будет легко выбрать, но пользователь хочет список пропущенных билетов между первым и последним билетом в системе.

Например Select TicketNr from Ticket order by TicketNr

Result
1,
2,
4,
7,
11

Но нам на самом деле нужен результат 3,5,6,8,9,10

CREATE TABLE [dbo].[Ticket](
[pknTicketId] [int] IDENTITY(1,1) NOT NULL,
[TicketNr] [int] NULL
) ON [PRIMARY]
GO

SQL Server 2016 - TSQL

Есть идеи?

Немногобольше информации нужно все решение до сих пор работает на маленьком столе.Наша производственная база насчитывает более 4 миллионов билетов.Следовательно, почему нам нужно найти пропавшие.

Ответы [ 6 ]

0 голосов
/ 01 июня 2018

Итак, посмотрев на все решения

, я приступил к созданию временной таблицы с полным диапазоном чисел от начального до конечного, а затем выбрал в таблице Temp, где номер билета отсутствует в билете..

Причина, по которой я продолжал работать с проблемами MAXRECURSION.

0 голосов
/ 01 июня 2018

Я думаю, что это даст вам самое простое решение

with cte as(
select max(TicketNr) maxnum,min(TicketNr) minnum from Ticket )

select a.number FROM master..spt_values a,cte
WHERE Type = 'P' and number < cte.maxnum and number > cte.minno
except 
select TicketNr FROM Ticket 
0 голосов
/ 01 июня 2018

Это должно сработать: SQL Fiddle

declare @ticketsTable table (ticketNo int not null)
insert @ticketsTable (ticketNo) values (1),(2),(4),(7),(11)
;with cte1(ticketNo, isMissing, sequenceNo) AS
(
    select ticketNo
    , 0
    , row_number() over (order by ticketNo) 
    from @ticketsTable
)
, cte2(ticketNo, isMissing, sequenceNo) AS
(
    select ticketNo, isMissing, sequenceNo
    from cte1

    union all

    select a.ticketNo + 1
    , 1
    , a.sequenceNo
    from cte2 a
    inner join cte1 b
    on b.sequenceNo = a.sequenceNo + 1
    and b.ticketNo != a.ticketNo + 1
)
select * 
from cte2 
where isMissing = 1
order by ticketNo

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

Затем мы можем увидеть пропуски в списке, найдя все места, где порядковый номер заказа показывает следующую запись, но номера билетов не являются последовательными.

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

0 голосов
/ 01 июня 2018

Если вы можете принять результаты в другом формате, следующее будет делать то, что вы хотите:

select TicketNr + 1 as first_missing,
       next_TicketNr - 1 as last_missing,
       (next_TicketNr - TicketNr - 1) as num_missing
from (select t.*, lead(TicketNr) over (order by TicketNr) as next_TicketNr
      from Ticket t
     ) t
where next_TicketNr <> TicketNr + 1;

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

Если вы используете рекурсивный CTE, я бы рекомендовал делать это только для отсутствующих билетов:

with cte as (
      select (TicketNr + 1) as missing_TicketNr
      from (select t.*, lead(TicketNr) over (order by TicketNr) as next_ticketNr
            from tickets t
           ) t
      where next_TicketNr <> TicketNr + 1
      union all
      select missing_TicketNr + 1
      from cte
      where not exists (select 1 from tickets t2 where t2.TicketNr = cte.missing_TicketNr + 1)
     )
select *
from cte;

Эта версия начинается со списка пропущенных номеров билетов.Затем он добавляет новый, так как номера не найдены.

0 голосов
/ 01 июня 2018

Один метод заключается в использовании recursive cte для поиска пропавшего ticket numbers:

with missing as (
      select min(TicketNr) as mnt, max(TicketNr) as mxt
      from ticket t
      union all
      select mnt+1, mxt
      from missing m
      where mnt < mxt
 )
select m.*
from missing m  
where not exists (select 1 from tickets t where t.TicketNr = m.mnt);
0 голосов
/ 01 июня 2018

Сначала получите минимальное и максимальное значения, затем сгенерируйте все возможные номера билетов и, наконец, выберите пропущенные.

;WITH FirstAndLast AS
(
    SELECT
        MinTicketNr = MIN(T.TicketNr),
        MaxTicketNr = MAX(T.TicketNr)
    FROM
        Ticket AS T
),
AllTickets AS
(
    SELECT
        TicketNr = MinTicketNr,
        MaxTicketNr = T.MaxTicketNr
    FROM
        FirstAndLast AS T

    UNION ALL

    SELECT
        TicketNr = A.TicketNr + 1,
        MaxTicketNr = A.MaxTicketNr
    FROM
        AllTickets AS A
    WHERE
        A.TicketNr + 1 <= A.MaxTicketNr
)
SELECT
    A.TicketNr
FROM
    AllTickets AS A
WHERE
    NOT EXISTS (
        SELECT
            'missing ticket'
        FROM
            Ticket AS T
        WHERE
            A.TicketNr = T.TicketNr)
ORDER BY
    A.TicketNr
OPTION
    (MAXRECURSION 32000)
...