我们公司向我们的承包商发行票据簿,我们跟踪书籍和书籍中的个人票证(每本书25张),以确保没有遗漏任何内容。我们的书是数字,书中的个人票也是。这本书与书中的第一张票相同。例如,票券101将包含票证101-125,票证簿126将包含票证126-150等......
每个承包商都会收到一本书,他们必须按顺序使用他们的门票。如果承包商有书101,他们必须按照101,102,103等的顺序使用门票......为了强制执行此操作,我们通过查找无序门票和显示来跟踪门票输入我们的数据库。这在报告中。例如,如果票证进入101,103,则必须在此报告中显示102作为缺失。
目前,这是我运行的SQL查询来检查:
select TicketNum, TicketBookNum, UnitID, DateIssued, IssuedBy
from TicketBooks a
where Used='No'
and TicketNum < (select MAX(b.TicketNum)
from TicketBooks b
where b.Used='Yes'
and b.UnitID=a.UnitID
and BookType='Truck' or BookType='Work'
and a.DateIssued <= b.DateIssued)
and BookType='Truck'
or BookType='Work'
order by DateIssued desc
此查询检索所有未使用的故障单,并将它们与已使用的故障单进行比较,以查看未使用的故障单号是否低于设备(承包商)的最高使用故障单号。如果它更低,则表示已跳过票证。再一个例子:使用了101,103,现在最高使用的票号是103而未使用的是102,这意味着它更低并且将显示在报告中。
我们公司有可能退票,并重新发行。在这种情况下,此报告的新售票簿编号可能不正常。例如:
现在这个SQL语句将把所有书籍151都归还为缺失,因为书籍201中使用的所有票证都是更高的票号和书籍151.我可以尝试只查找序列中的不按顺序记录。书,但我需要能够判断书中的最后一张票是否被跳过,并且是否使用了新书中的第一张票。
我想我需要做的是以某种方式考虑到本书的DateIssued以返回遗失的门票。
我一直在解决这个问题,所以任何帮助都不仅仅是非常感激。
这是我们数据库中的示例数据:
TicketNum | TicketBookNum | UnitID | DateIssued | IssuedBy
----------------------------------------------------------------------------
105073 105051 151 2016-04-23 10:02:40.000 kbusch
105074 105051 151 2016-04-23 10:02:40.000 kbusch
105075 105051 151 2016-04-23 10:02:40.000 kbusch
102801 102801 117 2016-04-22 10:19:23.000 kbusch
102802 102801 117 2016-04-22 10:19:23.000 kbusch
102803 102801 117 2016-04-22 10:19:23.000 kbusch
102804 102801 117 2016-04-22 10:19:23.000 kbusch
102805 102801 117 2016-04-22 10:19:23.000 kbusch
102806 102801 117 2016-04-22 10:19:23.000 kbusch
102807 102801 117 2016-04-22 10:19:23.000 kbusch
102808 102801 117 2016-04-22 10:19:23.000 kbusch
102809 102801 117 2016-04-22 10:19:23.000 kbusch
102810 102801 117 2016-04-22 10:19:23.000 kbusch
102811 102801 117 2016-04-22 10:19:23.000 kbusch
102812 102801 117 2016-04-22 10:19:23.000 kbusch
102813 102801 117 2016-04-22 10:19:23.000 kbusch
102814 102801 117 2016-04-22 10:19:23.000 kbusch
102815 102801 117 2016-04-22 10:19:23.000 kbusch
102816 102801 117 2016-04-22 10:19:23.000 kbusch
102817 102801 117 2016-04-22 10:19:23.000 kbusch
102818 102801 117 2016-04-22 10:19:23.000 kbusch
102819 102801 117 2016-04-22 10:19:23.000 kbusch
102820 102801 117 2016-04-22 10:19:23.000 kbusch
102821 102801 117 2016-04-22 10:19:23.000 kbusch
102822 102801 117 2016-04-22 10:19:23.000 kbusch
102823 102801 117 2016-04-22 10:19:23.000 kbusch
102824 102801 117 2016-04-22 10:19:23.000 kbusch
102825 102801 117 2016-04-22 10:19:23.000 kbusch
如您所见,票务本102801中的所有25张票都存在。造成这种情况的原因是因为该单位过去已经完成了票务手册103001。机票102801是无序发出的。我想要的预期输出不会显示这本书,因为它是最新的,但如果没有使用他们上一本书中的最后一张票,并且使用了本书中的第一张票,则该跳过的票将显示在此报告中。即使本书中的门票数量低于上一本书的数量。
为Tom H的解决方案编辑:一些丢失的门票没有显示。例如:
单元403具有于2015年4月2日发行的票券94801.单元403使用了票号94801-94815,但尚未使用票证94816-94825。此外,403单元于2015年7月1日发行了售票簿96751并使用了票据96751-96762,因此我需要本报告中显示的票证94816-94825。
另一个例子:
第142单元于2015年10月2日获得了售票簿99751,并使用了门票99751-99754而不是书中的最后一张票,票99775.从那时起,142号单元已经发行了几本书并使用了这些书中的所有票;因此,票据99775应显示在报告中。
EDIT2:
下面是显示403票的数据的图片
下面显示了您提供的查询返回的记录
答案 0 :(得分:1)
我相信这会给你你想要的东西。它会创建所有可能的票号的结果集,然后检查您的表中没有哪些票号。数字的两个CTE只是生成0到24的数字。请注意,如果您的票证大小可能会发生变化,这不是一个好的解决方案。此外,您可能应该有单独的TicketBooks
和Tickets
或UsedTickets
表。
;WITH CTE_TBs AS (
SELECT
TicketBookNum,
UnitID,
CASE WHEN LEAD(DateIssued) OVER (PARTITION BY UnitID ORDER BY DateIssued) IS NULL THEN 1 ELSE 0 END AS LastBook,
MAX(TicketNum) AS MaxTicketNum
FROM
(SELECT DISTINCT TicketBookNum, TicketNum, UnitID, DateIssued FROM TicketBooks) SQ -- Necessary because your database isn't properly normalized
GROUP BY
TicketBookNum, UnitID, DateIssued
),
CTE_Nums_1_5 AS (SELECT 1 AS num UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5),
CTE_Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY T1.num) - 1 AS num FROM CTE_Nums_1_5 AS T1 CROSS JOIN CTE_Nums_1_5 AS T2)
SELECT
TB.UnitID,
TB.TicketBookNum,
TB.TicketBookNum + N.num AS MissingTicketNum
FROM
CTE_TBs TB
LEFT OUTER JOIN CTE_Nums N ON (TB.TicketBookNum + N.num <= TB.MaxTicketNum) OR TB.LastBook = 0
WHERE
NOT EXISTS (SELECT * FROM TicketBooks WHERE TicketNum = TB.TicketBookNum + N.num)
答案 1 :(得分:1)
一旦承包商开始使用书籍,他必须在开始新书之前使用所有门票。
因此,对于给定的承包商,数据库中只有一本书(或没有)可以少于25行。如果给定的承包商在数据库中有多于一行且少于25行 - 则存在问题。
请注意,上述逻辑在发行书籍或承包商开始使用时并不关心。
CTE_IncompleteBooks
将所有门票分为承包商和书籍,计算每本书中使用的门票数量,并仅留下少于25张门票的书籍。
然后我们需要过滤那些只有一本不完整图书的承包商。
CTE_IncompleteBooksCount
为每个承包商计算不完整的图书。
最终SELECT
仅返回拥有多本不完整图书的承包商。
WITH
CTE_IncompleteBooks
AS
(
SELECT
UnitID
,TicketBookNum
,COUNT(*) AS UsedTicketCount
FROM TicketBooks
--WHERE Used=Yes -- not clear from the question whether you need this filter
GROUP BY
UnitID
,TicketBookNum
HAVING COUNT(*) < 25
)
,CTE_IncompleteBooksCount
AS
(
SELECT
UnitID
,TicketBookNum
,UsedTicketCount
,COUNT(*) OVER (PARTITION BY UnitID) AS IncompleteBookCount
FROM CTE_IncompleteBooks
)
SELECT
UnitID
,TicketBookNum
,UsedTicketCount
,IncompleteBookCount
FROM CTE_IncompleteBooksCount
WHERE IncompleteBookCount > 1
ORDER BY
UnitID
,TicketBookNum
;