如何在更新另一个 table 中的某些行时更新行?
How to update a row when certain rows in another table are updated?
我们有两个 table 订单和 order_products,
每个订单可以有多个order_products(因此,一对多关系)
CREATE TABLE orders (id UUID PK, status VARCHAR)
CREATE TABLE order_products (id UUID PK, order_id UUID FK, status VARCHAR)
order_products 使用消息代理并行处理。
当所有 order_products 已完成时,如何将订单状态设置为已完成?
理想情况下,我不想在订单上获得排他锁,因为那样 order_products 无法并行处理。
可能的解决方案:
在 orders
table 上定义 completed_order_products
并且每当 order_product
完成时,将 completed_order_products
的值递增 1,同时设置一个在 orders
上触发,因此在每次更新后,它会检查 completed_order_products
是否等于该订单的总数 order_products
。
提前致谢。
您可能会发现,通常 best/easiest 完成任务的方法就是不去做。这似乎是这里的情况。您的任务是确保仅在每个 order_product 状态完成时才指示订单完成。当更新 order_product 的状态时,您可以在不尝试更新订单的情况下完成此操作。相反,创建一个 VIEW 来确定整体 orders
与个人 order_products
的状态。下面是一种这样的方法。
首先用状态值创建一个 ENUM。现在枚举有一个有趣的顺序:
The ordering of the values in an enum type is the order in which the values were listed when the type was created. All standard comparison operators and related aggregate functions are supported for enums.
其次,为从枚举中选择最小值的订单创建一个视图。由于您没有指定完成以外的状态值,我将创建一个示例集。 (参见 demo here)
create type order_status_t as enum (
'pending',
'in progress',
'complete');
-- view for order status:
create view order_status as
( select order_id
, min(status) status
from order_products
group by order_id
);
-- get each order status:
select *
from order_status
order by order_id;
通过最小的更改,这可以通过查找 table 状态值及其相对序列而不是 enmu 来完成。
修订
正如我指出的那样,我认为你错过了重点。 order
上的状态本身并不存在,而是从状态值的组合中派生出来的,因此 未存储 ;因此不需要 CDC。但是,如果绝对需要,您可以保留 此时 订单状态列 但是复杂性会变得相当大。以下是一种方式,大约是我目前可以设计的最短方式。它需要添加:
- 触发器和触发器函数,用于更新“order_products”上每个 DML 操作的
order
状态。
- 用于在
orders
table. 上的每个 DML 上插入 CDC 的触发器和触发器函数
- 一个 stand-alone 函数从
order_product
状态值导出 order
状态。这将替换 VIEW。
- 添加 无产品 状态值 ENUM 类型(序列高于 Complete)。
查看代码和一些测试 here。这是一个非常极简主义 的例子,说明了需要什么。与往常一样,当您存储可导出值时,您可能会面临相当大的维护问题和性能问题。
我们有两个 table 订单和 order_products,
每个订单可以有多个order_products(因此,一对多关系)
CREATE TABLE orders (id UUID PK, status VARCHAR)
CREATE TABLE order_products (id UUID PK, order_id UUID FK, status VARCHAR)
order_products 使用消息代理并行处理。
当所有 order_products 已完成时,如何将订单状态设置为已完成?
理想情况下,我不想在订单上获得排他锁,因为那样 order_products 无法并行处理。
可能的解决方案:
在 orders
table 上定义 completed_order_products
并且每当 order_product
完成时,将 completed_order_products
的值递增 1,同时设置一个在 orders
上触发,因此在每次更新后,它会检查 completed_order_products
是否等于该订单的总数 order_products
。
提前致谢。
您可能会发现,通常 best/easiest 完成任务的方法就是不去做。这似乎是这里的情况。您的任务是确保仅在每个 order_product 状态完成时才指示订单完成。当更新 order_product 的状态时,您可以在不尝试更新订单的情况下完成此操作。相反,创建一个 VIEW 来确定整体 orders
与个人 order_products
的状态。下面是一种这样的方法。
首先用状态值创建一个 ENUM。现在枚举有一个有趣的顺序:
The ordering of the values in an enum type is the order in which the values were listed when the type was created. All standard comparison operators and related aggregate functions are supported for enums.
其次,为从枚举中选择最小值的订单创建一个视图。由于您没有指定完成以外的状态值,我将创建一个示例集。 (参见 demo here)
create type order_status_t as enum (
'pending',
'in progress',
'complete');
-- view for order status:
create view order_status as
( select order_id
, min(status) status
from order_products
group by order_id
);
-- get each order status:
select *
from order_status
order by order_id;
通过最小的更改,这可以通过查找 table 状态值及其相对序列而不是 enmu 来完成。
修订
正如我指出的那样,我认为你错过了重点。 order
上的状态本身并不存在,而是从状态值的组合中派生出来的,因此 未存储 ;因此不需要 CDC。但是,如果绝对需要,您可以保留 此时 订单状态列 但是复杂性会变得相当大。以下是一种方式,大约是我目前可以设计的最短方式。它需要添加:
- 触发器和触发器函数,用于更新“order_products”上每个 DML 操作的
order
状态。 - 用于在
orders
table. 上的每个 DML 上插入 CDC 的触发器和触发器函数
- 一个 stand-alone 函数从
order_product
状态值导出order
状态。这将替换 VIEW。 - 添加 无产品 状态值 ENUM 类型(序列高于 Complete)。
查看代码和一些测试 here。这是一个非常极简主义 的例子,说明了需要什么。与往常一样,当您存储可导出值时,您可能会面临相当大的维护问题和性能问题。