2014-01-23 112 views
0

我有一个类似的表:如何实现UPSERT与附加标准

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

我试图做操作的插入,或更新型的数据库上。我想实现的逻辑是:

  1. 如果记录已经给定order_id和给定的owner_id匹配存在,则更新记录
  2. 否则,如果记录已经给定的order_id存在,以及给定owner_id不匹配,则抛出一个错误
  3. 否则,插入新记录

理想我想实现它使用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的方式解决它。

+0

使用触发器......即他们的工作。 –

+0

你的意思是,定义一个触发器,如果​​UPDATE尝试更改owner_id的值,则会引发错误...实际上这不是一个坏主意 – harmic

回答

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(); 

已经定义了这个,然后我定义的UPSERT过程之多,在PG docs描述的相同。

感谢@Noran给我的想法。