SQL查询帮助 - 否定报告

时间:2018-06-01 09:35:33

标签: sql sql-server tsql sql-server-2016

也许有人可以帮助创意或解决方案。用户要求我提供负面报告。我们有一张带票的表,每张票都有一个票号,这个号码很容易选择,但是用户想要系统中第一张和最后一张票之间缺少票的列表。

E.g。 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

有什么想法吗?

所以需要更多的信息到目前为止所有解决方案都适用于小型表。我们的生产数据库有超过400万张门票。因此,为什么我们需要找到遗漏的那些。

6 个答案:

答案 0 :(得分:2)

首先获得最小值和最大值,然后生成所有可能的票号,最后选择丢失的号码。

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

答案 1 :(得分:2)

如果您可以采用其他格式接受结果,则以下内容将按您的要求执行:

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;

此版本以缺少的票号列表开头。然后添加一个新的,因为找不到数字。

答案 2 :(得分:1)

一种方法是使用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);

{{1}}

答案 3 :(得分:1)

这应该可以解决问题: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

它的工作原理是收集所有现有的票证,将它们标记为现有票据,并为每个票据分配一个连续号码,在原始列表中给出他们的订单。

然后,我们可以通过查找连续订单号显示下一条记录的任何地点来查看列表中的空白,但票号不是连续的。

最后,我们递归填补空白;从差距开始工作并添加新记录,直到差距的连续数字在相关的票号之间不再有差距。

答案 4 :(得分:1)

我认为这个可以为您提供最简单的解决方案

stat

答案 5 :(得分:0)

所以看完所有解决方案后

我创建了一个临时表,其中包含从“开始”到“结束”票证的全部数字,然后从“临时”表中选择,票号不在票证表中。

原因是我一直在运行MAXRECURSION问题。