Continuous sequences in SQL

The presence of a table with the following fields:

Order, group, sequence

it is required that all orders in a given group form a continuous sequence. For example: 1,2,3,4 or 4,5,6,7. How can I check, using a single SQL query, which orders do not match this rule? Thanks.

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

      

Also accepted if the query only returns a group that has the wrong sequence, 2 for example data.

+1


a source to share


6 answers


Assuming the sequences are generated and therefore cannot be duplicated:




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

      

+4


a source


How about this?

select a group from the table
group by group
(Sequence) <= max (Sequence) -min (Sequence)

[Edit] This assumes the Sequence does not allow duplicates in a specific group. Better to use:
count! = Max - min + 1



[Edit again] D'O, still not perfect. Another request, to clean up duplicates, will take care of this.

[Edit last] The original query worked fine in sqlite and this is what I had for a quick test. It is much more forgiving than SQL Server. Thanks Bell for the pointer.

+2


a source


Personnel. I think I would consider rethinking this requirement. It is the nature of relational databases that sequence gaps can easily be caused by rolling back records. For example, suppose an order starts creating four items in it, but one of them fails for some rason and rolls back. If you pre-computed the sequences by hand, then you have a gap that is not rolled back last. In other scenarios, you might get a break due to multiple users searching for sequence values ​​at approximately the same time, or if the customer deleted one record from the order at the last moment. What do you honestly want to get out of the continuous sequences that you don't get from parenting with your kids?

+2


a source


This SQL selects orders 3 and 4, which have no contiguous sequences.

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

      

+1


a source


So your table is in the form

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

      

.. and you want to know what 1,1,6 is missing?

FROM

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

      

you can find out the limits for a given order and group.

Now you can simulate the correct data using the special numbers table , which contains only every number you could ever use for a sequence. Here is a good example of such a table of numbers. It doesn't matter how you create it, you can also create an excel file with all numbers from x to y and import that excel sheet.

In my example I am assuming a table of numbers like this called "Numbers" with only one column "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

      

Place this SQL in a new view. In my example, I will call the view "vwCorrectOrders".

This gives you data in which the sequences are continuous. Now you can join this data with the original data to find out which sequences are missing:

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

      

Gotta give you

Order Group Sequence
1     1     6

      

0


a source


After a while, I came up with the following solution. It seems to work, but it is very inefficient. Please add suggestions for improvement.

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


a source







All Articles