Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
POSTGRESQL类外键约束_Postgresql - Fatal编程技术网

POSTGRESQL类外键约束

POSTGRESQL类外键约束,postgresql,Postgresql,我有一张名为Order 它有一个PKid多个列,一个名为active的bool列和一个tableid列。对于一个表ID,不能同时激活两个订单,该表ID由一个类似索引的两列唯一约束(&&active=true)确保,并且查找活动订单非常快。 问题是还有另一个表orderitems。我希望active为true,除非订单id的所有orderitems都标记为paid=true。 使用序列化事务,我认为在支付代码中,如果所有项目都已支付,则可以通过设置更新查询来实现这一点。我认为这不会一直有效。因为如

我有一张名为Order

它有一个PKid多个列,一个名为
active
的bool列和一个tableid列。对于一个表ID,不能同时激活两个订单,该表ID由一个类似索引的两列唯一约束(&&active=true)确保,并且查找活动订单非常快。
问题是还有另一个表orderitems。我希望active为true,除非订单id的所有orderitems都标记为paid=true。
使用序列化事务,我认为在支付代码中,如果所有项目都已支付,则可以通过设置更新查询来实现这一点。我认为这不会一直有效。因为如果它们同时运行,它们可能都会看到有未支付的项目(由于旧快照),但在提交时,它们会支付所有项目,但不会更新活动列。(不同)。
添加新项目和付款交易尝试设置active=false对于串行交易不会有问题,因为其中一个交易会失败。

我认为触发器是一个解决方案,但我不知道该怎么做。。感谢您阅读

您要做的是在更新后添加一个
,或者在
orderitems
上为每一行插入或删除触发器,以确定是否应更改
Order.active
。你必须做一个
选择。。。对于拥有这些
orderitems
Order
行上的更新
,否则您将面临触发器同时运行、相互竞争和执行无序更新的风险

假定
orderitems
有一个字段
order\u id
,该字段是您对
order.id
的外键引用,请尝试以下类似代码(未测试,仅适用于一般示例):

CREATE OR REPLACE FUNCTION orderitems_order_active_trigger() RETURNS trigger AS $$
DECLARE
  _old_active BOOLEAN;
  _new_active BOOLEAN;
  _order_id INTEGER;
BEGIN
  IF tg_op = 'INSERT' THEN
    _order_id = NEW.order_id;
  ELIF tg_op = 'UPDATE' THEN
    _order_id = NEW.order_id;
  ELIF tg_op = 'DELETE' THEN
    _order_id = OLD.order_id;
  ELSE
    RAISE EXCEPTION 'Unexpected trigger operation %',tg_op;
  END IF;
  -- Lock against concurrent trigger runs and other changes in the parent record while
  -- obtaining the current value of `active`
  SELECT INTO _old_active Order.active FROM Order WHERE Order.id = _order_id FOR UPDATE;
  -- Now figure out whether the order should be active. We'll say that if there are
  -- more than zero unpaid order items found we'll treat it as active.
  _new_active = EXISTS(SELECT 1 FROM orderitems WHERE orderitems.order_id = _order_id AND orderitems.paid='f');
  -- If the active state has flipped, update the order.
  IF _old_active IS DISTINCT FROM _new_active THEN
    UPDATE Order SET active = _new_active WHERE Order.id = _order_id;
  END IF;
END;
$$ LANGUAGE 'plpgsql' VOLATILE;

CREATE TRIGGER orderitems_ensure_active_correct AFTER INSERT OR UPDATE OR DELETE 
ON orderitems FOR EACH ROW EXECUTE PROCEDURE orderitems_order_active_trigger();

正确的想法…触发器函数将能够处理这个问题。orderitems是否更新为设置为paid=true?还是插页?在任何情况下都要使用表格funks:Postgres文档。。。拼写检查将funcs改为funks。哈use table funks=use trigger funcs。问题是:在没有触发器的情况下是否可以完成此操作?请添加相关的表定义,包括键和约束,好吗?这可以节省一些人在9.1中使用新的true
SERIALIZABLE
模式键入的时间…@wildplasser我想如果你总是小心翼翼地进行
选择,这是可能的。。。用于在插入新订单项目时对订单进行更新。您必须执行
选择。。。用于更新
,因为仍然没有谓词锁定;当另一个事务正在查看具有相同订单ID的其他OrderItem时,它无法知道新插入的订单项是否会破坏可序列化性。因此,我建议在触发器中执行此操作。在9.1中,他们说存在谓词锁定。使用更新进行测试有效,但我没有使用插入进行测试