2010-12-20 103 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;