2

数据库正在从流中提取数据,满足外键约束所需的所有行可能会延迟或永远不会到达。

这可以通过使用另一个数据存储来完成,一个没有外键约束的数据存储,然后当所有需要的数据都可用时,读入具有 fk 约束的数据库。但是,这增加了复杂性,我想避免它。

我们正在研究一种创建“占位符”行以将外键指向的解决方案。当真实数据进来时,占位符被替换为真实值。同样,这增加了复杂性,但这是迄今为止我们找到的最佳解决方案。

人们通常如何解决这个问题?

编辑:一些可能有助于解释问题的示例数据:

假设我们有这些表:

CREATE TABLE order (
  id INTEGER NOT NULL,
  order_number,
  PRIMARY KEY (id),
  UNIQUE (order_number)
);

CREATE TABLE line_item (
  id INTEGER NOT NULL,
  order_number INTEGER REFERENCES order(order_number),
  PRIMARY KEY (id)
);

如果我先下单,没问题!但是,假设我尝试:

INSERT INTO line_item (order_number) values (123)在插入订单 123 之前。这当然会使 fk 约束失败。但这可能是我获取数据的顺序,因为它是从从多个来源收集这些数据的流中读取的。

另外,为了解决@philpxy 的问题,我对此并没有真正找到太多。提到的一件事是延迟约束。这是一种在事务结束时等待执行 fk 约束的机制。但是,我认为在我的情况下不可能这样做,因为这些插入语句将在收到数据时随机运行。

4

2 回答 2

1

您有一个业务工作流问题,因为单个订单的行项目在订单本身进入之前进入。一种可能不理想的解决方法是创建一个插入前触发器,该触发器检查每个进入line_item表的插入,该订单是否已存在于order表中。如果没有,那么它会先插入订单记录,然后再尝试插入line_item

CREATE OR REPLACE FUNCTION "public"."fn_insert_order" () RETURNS trigger AS $$
BEGIN
    INSERT INTO "order" (order_number)
    SELECT NEW.order_number
    WHERE NOT EXISTS (SELECT 1 FROM "order" WHERE order_number = NEW.order_number);
    RETURN NEW;
END
$$
LANGUAGE 'plpgsql'

# trigger 
CREATE TRIGGER "trigger_insert_order"
BEFORE INSERT ON line_item FOR EACH ROW
EXECUTE PROCEDURE fn_insert_order()

注意:我假设表的idorder实际上是自动递增的,在这种情况下,Postgres 会在插入时自动为其分配一个值。这很可能是您想要的,因为有两个需要手动分配的 id 列没有多大意义。

于 2020-01-14T06:08:08.197 回答
1

您可以使用BEFORE INSERT触发器来完成此操作line_item。在该触发器中,您查询order是否存在匹配项,如果不存在,则插入一个虚拟行。

这将允许INSERT成功,但会牺牲一些性能。

要将行插入order,请使用

INSERT INTO order ...
ON CONFLICT ON (order_number) DO UPDATE SET
   id = EXCLUDED.id;

更新主键是有问题的,可能会导致冲突。解决这个问题的一种方法是,如果您id对人工生成的订单使用负数(假设实数id是正数)。如果您对该主键有任何引用,则必须使用ON UPDATE CASCADE.

于 2020-01-14T06:11:54.507 回答