MySQL递归cte基本情况

问题描述

我有一堆聚合的事件表(order 是其中之一),我可以像这样查询

SELECT * FROM events WHERE aggregate_id = :order_id AND aggregate_type = :order_type

这适用于简单的情况,但它会更多地涉及 duplicate created 事件。业务需求之一是订单可以重复(从概念上讲,请考虑move,而不是copy)。这将关闭原始订单,然后工作人员可以继续处理新订单。为了显示订单的完整历史记录,不仅要显示当前订单的事件,还要显示任何原始订单上的事件。

这是一个简化的例子:

订单 3

  • 5 月 10 日 - 发货
  • 5 月 9 日 - 打包
  • 5 月 9 日 - 复制自 Order 2

订单 2

  • 5 月 9 日 - 关闭
  • 5 月 8 日 - 联系了客户
  • 5 月 8 日 - 收到库存
  • 5 月 6 日 - 复制自 Order 1

订单 1

  • 5 月 6 日 - 关闭
  • 5 月 5 日 - 创建

我提出了一个相当简单的查询,适用于这种情况:

WITH RECURSIVE original_orders(order_id) AS (
  select aggregate_id
  from events
  where aggregate_type = 'order'
    and aggregate_id = :order_id
    and event_name = 'duplicate created'
  UNION ALL
  select body->'$.duplicatedFromOrderId'
  from original_orders
    inner join events on (aggregate_type = 'order' and aggregate_id = order_id and event_name = 'duplicate created')
)
SELECT events.*
FROM events
INNER JOIN original_orders ON aggregate_id = order_id;
-- extra context from the real (not simplified) use-case:
-- I actually use the CTE twice,because "notes" are stored separately
-- INNER JOIN users ON event.user_id - to get more info
-- UNION ALL SELECT * FROM notes JOIN original_orders ON order_id = notes.object_id

递归 CTE 最终选择从最新订单(基本情况部分)开始的订单 ID,然后通过从事件正文中获取原始订单 ID 进行递归。 该示例的结果将是具有 3 行的单列 order_id(3,2,1)

问题在于,如果我们查看原始订单(在本例中为订单 1),根本不会显示任何事件,因为它没有重复创建事件。因此,任何不重复的订单在基本情况下都不会选择任何内容,因此 CTE 将返回一个空结果集。

我觉得我的逻辑有些缺陷,而且我缺少[明显]简单的方法来获得我需要的东西。我认为在基本情况下,我可以改为搜索 ANY 事件名称和 GROUP BY id,从而在基本情况查询中获得 order_id,即使订单不是重复的(以类似的方式我可以使用 SELECT DISTINCT 并放弃 GROUP BY 但它实际上是同一件事)。像这样:

WITH RECURSIVE original_orders(order_id) AS (
  select aggregate_id
  from events
  where aggregate_type = 'order'
    and aggregate_id = :order_id
  group by aggregate_id
  UNION ALL
  -- ...
)

这感觉像是一种解决方法,所以我很想修正我的逻辑。我错过了什么?


可重现的例子:

create table events
(
    id             int auto_increment,aggregate_type varchar(100) not null,aggregate_id   varchar(255) not null,event_name     varchar(255) not null,occurred_on    datetime     not null,body           json         not null,constraint events_pk
        primary key (id)
);

insert into events (aggregate_type,aggregate_id,event_name,occurred_on,body)
values ('order',1,'created','2020-05-05 09:00:00',json_object()),('order','closed','2020-05-06 09:00:00','duplicate created',json_object('duplicatedFromOrderId',1)),'received','2020-05-07 09:00:00','2020-05-08 09:00:00',3,2)),'shipped','2020-05-09 09:00:00',json_object());

使用 :order_id = 3 运行查询应返回所有 7 个事件。

使用 :order_id = 2 运行查询应返回 5 个事件(应忽略​​订单 3 的事件)。

使用 :order_id = 1 运行查询应返回 2 个事件。

解决方法

AND GPA < 3

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...