2010-12-20 109 views
0

我使用的PostgreSQL(8.3+)和如下所定义的枚举和桌子的PostgreSQL的存储过程:添加逻辑以

CREATE TYPE "viewer_action" AS ENUM ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'); 

CREATE TABLE "preferences" ( 
    "user_id"  integer NOT NULL, 
    "item_id"  integer NOT NULL, 
    "rating"  viewer_action NOT NULL, 
    "time_created" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    PRIMARY KEY ("user_id","video_id") 
); 

我还创建了一个存储过程来UPSERT新行插入偏好表,利用从 http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE的例子:

CREATE OR REPLACE FUNCTION add_preference(u INT, i INT, r viewer_action) RETURNS VOID AS $add_preference$ 
    BEGIN 
     LOOP 
      -- first try to update the key 
      UPDATE preferences SET rating = r WHERE user_id = u AND item_id = i; 
      IF found THEN 
       RETURN; 
      END IF; 
      -- not there, so try to insert the key 
      -- if someone else inserts the same key concurrently, 
      -- we could get a unique-key failure 
      BEGIN 
       INSERT INTO preferences(user_id,item_id,rating) VALUES (u,i,r); 
       RETURN; 
      EXCEPTION WHEN unique_violation THEN 
       -- do nothing, and loop to try the UPDATE again 
      END; 
     END LOOP; 
    END; 
$add_preference$ LANGUAGE plpgsql; 

我需要一些额外的逻辑添加到更新插入,以防止覆盖其他值的一些值。具体做法是:

  • A可被B,其可以被C通过覆盖,其可以通过d通过F.被覆盖,等等,但是不能被由A覆盖B,和C都以B,等覆盖被覆盖。
  • 无论现有值是低还是高,F,G或H都可以覆盖任何值。

伪代码,这可能是这样的:

if (rating >= F) { 
    insert; 
} else if (rating > existing_rating) { 
    insert; 
} else { 
    return; 
} 
+3

plpgsql支持控制流。看起来好像你可以直接实现你的代码。 – 2010-12-20 22:39:10

回答

1

创建之前插入或更新此表上的触发器。为此,你可以使用你的函数,只需要将返回类型改为TRIGGER。

BEFORE触发器在将行插入表之前触发,因此您可以在写入数据之前检查它们。在触发器

的更多信息,你可以在这里找到:
http://www.postgresql.org/docs/9.0/interactive/plpgsql-trigger.html

0

难道你不能用case语句做些什么吗?

就是这样。

--If new rating is greater than existing rating update it else update to current value. 
    UPDATE preferences 
    SET rating = CASE WHEN r > rating THEN r ELSE rating END;