SQL 中的连续序列

发布于 2024-07-19 08:49:38 字数 327 浏览 4 评论 0原文

有一个包含以下字段的表:

订单、组、序列,

要求给定组中的所有订单形成连续序列。 例如: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),也可接受。

Having 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 what orders do not comply with this rule? Thank you.

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 returns only the group which has the wrong sequence, 2 for the example data.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

失与倦" 2024-07-26 08:49:38

假设序列已生成,因此不能重复:


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

Assuming that the sequences are generated and therefore cannot be duplicated:


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

芯好空 2024-07-26 08:49:38

这个怎么样?

从表中选择组
按组分组
具有 count(Sequence) <= max(Sequence)-min(Sequence)

[编辑] 这假设 Sequence 不允许在特定组内出现重复项。 使用以下方法可能会更好:
count != max - min + 1

[再次编辑] D'oh,仍然不完美。 不过,另一个清除重复项的查询可以解决这个问题。

[编辑最后一个] 原始查询在 sqlite 中运行良好,这是我可用于快速测试的。 它比 SQL Server 更宽容。 感谢贝尔的指点。

How about this?

select Group from Table
group by Group
having count(Sequence) <= max(Sequence)-min(Sequence)

[Edit] This assumes that Sequence does not allow duplicates within a particular group. It might be better to use:
count != max - min + 1

[Edit again] D'oh, still not perfect. Another query to flush out duplicates would take care of that though.

[Edit the last] The original query worked fine in sqlite, which is what I had available for a quick test. It is much more forgiving than SQL server. Thanks to Bell for the pointer.

怪我入戏太深 2024-07-26 08:49:38

我个人认为我会考虑重新考虑这个要求。 关系数据库的本质是,由于记录回滚,很容易出现序列间隙。 例如,假设一个订单开始在其中创建四个项目,但其中一个因某些原因失败并被回滚。 如果您手动预先计算序列,则会出现间隙,因为回滚的不是最后一个。 在其他情况下,由于多个用户几乎同时查找序列值,或者客户在最后一刻从订单中删除了一条记录,您可能会遇到间隙。 老实说,您希望从父子关系中无法获得的连续序列中获得什么?

Personaly I think I would consider rethinking the requirement. It is the nature of relational databases that gaps in sequences can easily occur due to records that are rolled back. For instance, supppose an order starts to create four items in it, but one fails for some rason and is rolled back. If you precomputed the sequences manually, you would then have a gap is the one rolled back is not the last one. In other scenarios, you might get a gap due to multiple users looking for sequence values at approximately the same time or if at the last minute a customer deleted one record from the order. What are you honestly looking to gain from having contiguous sequences that you don't get from a parent child relationship?

二货你真萌 2024-07-26 08:49:38

此 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

This SQL selects the orders 3 and 4 wich have none continuous 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
旧城烟雨 2024-07-26 08:49:38

所以你的表的形式是

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]

可以使用它找出给定订单和组的范围。

现在,您可以使用特殊的数字表来模拟正确的数据,该表仅包含您可以用于序列的每个数字。 这里是此类数字表的一个很好的示例。 如何创建它并不重要,您还可以创建一个包含从 x 到 y 的所有数字的 Excel 文件,然后导入该 Excel 工作表。

在我的示例中,我假设有一个名为“Numbers”的数字表,只有一列“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

So your table is in the form of

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

..and you want to find out that 1,1,6 is missing?

With

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

you can find out the bounds for a given Order and Group.

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

In my example I assume such a numbers table 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

Put that SQL into a new view. In my example I will call the view "vwCorrectOrders".

This gives you the data where the sequences are continuous. Now you can join that 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

Should give you

Order Group Sequence
1     1     6
绝不服输 2024-07-26 08:49:38

一段时间后,我想出了以下解决方案。 这似乎有效,但效率极低。 请添加任何改进建议。

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

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

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))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文