2016-05-12 4 views
4

Наша компания выпускает книги для подписчиков нашим подрядчикам, и мы отслеживаем как книги, так и индивидуальные билеты внутри книг (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, то есть он ниже и будет отображаться в отчете.

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

  • подрядчик использует книгу по продаже билетов 201
  • Contractor B покидает компанию и возвращается по продаже билетов книге 151
  • подрядчика заканчивает книгу по продаже билетов 201
  • подрядчика получает новый билет книгу из офиса. Это билетная книга 151

Теперь этот оператор 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 

Как вы можете видеть, все 25 билетов в ticketbook 102801 присутствует. Причиной этого является то, что в прошлом блок уже заполнял билетную книжку 103001. Билетная книга 102801 вышла из строя. Ожидаемый результат, который я бы хотел, не отобразил бы эту книгу, потому что она самая новая, но если последний билет в их предыдущей книге не использовался, а первый билет в этой книге был использован, то этот пропущенный билет будет отображаться в этом отчете , Несмотря на то, что билеты в этой книге имеют меньшее количество, чем предыдущая книга.

EDIT для решения Tom H: некоторые отсутствующие билеты не отображаются.Например:

Блок 403 имеет билетную книгу 94801, которая была выпущена 2 апреля 2015 года. Устройство 403 использовало билеты 94801-94815, но еще не использовало билеты 94816-94825. Кроме того, Unit 403 был выпущен билетной книжкой 96751 1 июля 2015 года и использовал билеты 96751-96762, поэтому мне нужны билеты 94816-94825, представленные в этом отчете.

Другой пример:

Unit 142 была выпущена книга билет 99751 на 2 октября 2015 года и использовал билеты 99751-99754, но не последний билет в книге, билетные 99775. Блок 142 было издано несколько книг, так как затем и использовал все билеты в этих книгах; поэтому в отчете должен отображаться билет 99775.

EDIT2:

Ниже приводится изображение, показывающее данные для 403 в билетах

enter image description here

Ниже показаны записи возвращаются из запроса вы предоставили

enter image description here

+0

Ожидаемый результат? – mxix

+0

У вас есть столбцы в вашем запросе (например, 'used'), которые не отображаются в ваших данных образца. Каждый билет появляется в вашем столе? –

+3

Это проблема «Пробелы и острова», и если вы используете этот термин, вы найдете много примеров. –

ответ

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) 
+0

Спасибо за ответ, Том. Я только что вернулся с обеда, поэтому я перейду к этому и ответу вам скоро. –

+0

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

+0

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

1

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

Таким образом, для данного подрядчика только одна книга (или ее нет) в базе данных может содержать менее 25 строк. Если у конкретного подрядчика имеется более одной книги в базе данных с менее чем 25 строками - возникает проблема.

Обратите внимание, что логика выше не заботится о том, когда книга была выпущена, или подрядчик начал ее использовать.

группирует все билеты в подрядчики и книги, подсчитывает, сколько билетов было использовано в каждой книге и оставляет только те книги, у которых менее 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 
; 
+0

Извините, я не видел вашего ответа, поскольку я не был рядом с моим компьютером. Я взгляну на это скоро и ответю вам. Благодарю. –

Смежные вопросы