Непрерывные последовательности в SQL - PullRequest
1 голос
/ 18 мая 2009

Имея таблицу со следующими полями:

Заказать, Группа, последовательность

требуется, чтобы все заказы в данной группе образовывали непрерывную последовательность. Например: 1,2,3,4 или 4,5,6,7. Как я могу проверить с помощью одного SQL-запроса, какие заказы не соответствуют этому правилу? Спасибо.

Example data:

Order   Group   Sequence
1   1   3
2   1   4
3   1   5
4   1   6
5   2   3
6   2   4
7   2   6

Expected result:
Order
5
6
7

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

Ответы [ 6 ]

4 голосов
/ 18 мая 2009

Предполагая, что последовательности генерируются и, следовательно, не могут быть дублированы:


SELECT group
 FROM theTable
 GROUP BY group
 HAVING MAX(Sequence) - MIN(Sequence) &lt> (COUNT(*) - 1);

2 голосов
/ 18 мая 2009

Лично я думаю, что я бы рассмотрел переосмысление требования. Природа реляционных баз данных заключается в том, что разрывы в последовательностях могут легко возникать из-за отката записей. Например, предположим, что заказ начинает создавать в нем четыре элемента, но один не выполняется для какого-то rason и откатывается. Если вы предварительно вычислите последовательности вручную, у вас будет разрыв, если откат не последний. В других сценариях вы можете получить пробел из-за того, что несколько пользователей ищут значения последовательности примерно в одно и то же время или если в последнюю минуту клиент удалил одну запись из заказа. Что вы, честно говоря, рассчитываете получить от смежных последовательностей, которые вы не получаете от отношений родитель-ребенок?

2 голосов
/ 18 мая 2009

Как насчет этого?

выберите группу из таблицы
группировать по группам
имеющий количество (последовательность) <= max (последовательность) -мин (последовательность) </p>

[Редактировать] Предполагается, что последовательность не допускает дублирования в определенной группе. Может быть лучше использовать:
count! = Max - min + 1

[Снова отредактируйте] О, все еще не идеально. Об этом позаботится еще один запрос на удаление дубликатов.

[Изменить последний] Исходный запрос отлично работал в sqlite, что я и имел для быстрого тестирования. Это гораздо более снисходительно, чем SQL-сервер. Спасибо Беллу за указатель.

1 голос
/ 18 мая 2009

Этот SQL выбирает порядки 3 и 4, которые не имеют непрерывных последовательностей.

DECLARE @Orders TABLE ([Order] INTEGER, [Group] INTEGER, Sequence INTEGER)

INSERT INTO @Orders VALUES (1, 1, 0)
INSERT INTO @Orders VALUES (1, 2, 0)
INSERT INTO @Orders VALUES (1, 3, 0)

INSERT INTO @Orders VALUES (2, 4, 0)
INSERT INTO @Orders VALUES (2, 5, 0)
INSERT INTO @Orders VALUES (2, 6, 0)

INSERT INTO @Orders VALUES (3, 4, 0)
INSERT INTO @Orders VALUES (3, 6, 0)

INSERT INTO @Orders VALUES (4, 1, 0)
INSERT INTO @Orders VALUES (4, 2, 0)
INSERT INTO @Orders VALUES (4, 8, 0)

SELECT o1.[Order]
FROM @Orders o1
     LEFT OUTER JOIN @Orders o2 ON o2.[Order] = o1.[Order] AND o2.[Group] = o1.[Group] + 1
WHERE o2.[Order] IS NULL
GROUP BY o1.[Order]
HAVING COUNT(*) > 1
0 голосов
/ 18 мая 2009

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

SELECT OrdMain.Order
  FROM ((Orders AS OrdMain
  LEFT OUTER JOIN Orders AS OrdPrev ON (OrdPrev.Group = OrdMain.Group) AND (OrdPrev.Sequence = OrdMain.Sequence - 1))
  LEFT OUTER JOIN Orders AS OrdNext ON (OrdNext.Group = OrdMain.Group) AND (OrdNext.Sequence = OrdMain.Sequence + 1))
WHERE ((OrdMain.Sequence < (SELECT MAX(Sequence) FROM Orders OrdMax WHERE (OrdMax.Group = OrdMain.Group))) AND (OrdNext.Order IS NULL)) OR
      ((OrdMain.Sequence > (SELECT MIN(Sequence) FROM Orders OrdMin WHERE (OrdMin.Group = OrdMain.Group))) AND (OrdPrev.Order IS NULL))
0 голосов
/ 18 мая 2009

Итак, ваш стол в форме

Order Group Sequence
1     1     4
1     1     5
1     1     7

.. а вы хотите узнать, что 1,1,6 отсутствует?

С

select
  min(Sequence) MinSequence, 
  max(Seqence) MaxSequence 
from 
  Orders 
group by 
  [Order], 
  [Group]

Вы можете узнать границы для данного Ордена и Группы.

Теперь вы можете смоделировать правильные данные, используя специальную таблицу чисел , которая содержит только все числа, которые вы когда-либо могли использовать для последовательности. Здесь является хорошим примером такой таблицы чисел. Не важно, как вы его создадите, вы также можете создать файл Excel со всеми числами от x до y и импортировать этот лист Excel.

В моем примере я предполагаю такую ​​таблицу чисел, которая называется «Числа» только с одним столбцом «n»:

select 
  [Order], 
  [Group], 
  n Sequence
from
  (select min(Sequence) MinSequence, max(Seqence) MaxSequence from [Table] group by [Order], [Group]) MinMaxSequence
  left join Numbers on n >= MinSequence and n <= MaxSequence

Поместите этот SQL в новое представление. В моем примере я назову представление "vwCorrectOrders".

Это дает вам данные, где последовательности являются непрерывными. Теперь вы можете объединить эти данные с исходными данными, чтобы выяснить, какие последовательности отсутствуют:

select 
  correctOrders.*
from
  vwCorrectOrders co 
  left join Orders o on 
      co.[Order] = o.[Order] 
  and co.[Group] = o.[Group]
  and co.Sequence = o.Sequence
where
  o.Sequence is null

Должно дать вам

Order Group Sequence
1     1     6
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...