如何使用其他条件实现upsert

时间:2014-01-23 03:35:13

标签: postgresql postgresql-9.2

我有一张类似的表:

CREATE TABLE orders(
    order_id UUID PRIMARY KEY,
    owner_id TEXT,
    other_data TEXT
)

我正在尝试对数据库执行insert-or-update类型的操作。我试图实现的逻辑是:

  1. 如果已存在包含给定order_id的记录,并且给定的owner_id匹配,则更新记录
  2. 否则,如果已存在具有给定order_id的记录,且给定的owner_id不匹配,则抛出错误
  3. 否则,请插入新记录
  4. 理想情况下,我希望使用postgresql文档中的custom UPSERT example将其实现为存储过程。

    我遇到的问题是区分案例1和案例2.上面的案例,而不必进行两次单独的查询。如果我这样做:

    UPDATE orders(other_data) WHERE order_id=order_id_param AND owner_id=owner_id_param;
    

    然后如果没有匹配的订单我不知道是不是因为记录不存在,或者确实存在但owner_id不匹配。

    当然,我可以在更新之前进行这样的初始查询:

    SELECT count(1) FROM orders WHERE order_id=order_id_param AND owner_id!=owner_id_param;
    

    如果返回的计数> 0,则抛出错误;但是如果可能的话,我想避免额外的查询。

    我正在使用PostgreSQL 9.2。

    我发现this similar SO question但它适用于SQL Server 2008,并且似乎没有以我可以简单地应用于PostgreSQL的方式解决它。

1 个答案:

答案 0 :(得分:0)

最后,我通过定义一个触发器来解决这个问题,如果owner_id不匹配,该触发器会阻止表上的UPDATE查询成功。

这很简单,看起来像这样:

CREATE OR REPLACE FUNCTION order_update_check() 
RETURNS trigger
AS $$
BEGIN
    IF NEW.owner_id != OLD.owner_id THEN
        RAISE EXCEPTION 'User % cannot modify order %', NEW.owning_user, OLD.order_id;
    END IF;
    RETURN NEW;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER order_update_trigger BEFORE UPDATE ON orders
    FOR EACH ROW EXECUTE PROCEDURE order_update_check();

在定义了这个之后,我定义了一个与PG docs中描述的相同的upsert过程。

感谢@Noran给我的想法。