也许有人可以帮助创意或解决方案。用户要求我提供负面报告。我们有一张带票的表,每张票都有一个票号,这个号码很容易选择,但是用户想要系统中第一张和最后一张票之间缺少票的列表。
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万张门票。因此,为什么我们需要找到遗漏的那些。
答案 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问题。