Я использую PostgreSQL (8.3+) и определил перечисление и таблицу следующим образом:
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")
);
Я также создал хранимую процедуру для добавления новых строк в таблицу предпочтений, используяпример из 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;
Мне нужно добавить некоторую дополнительную логику в upsert, чтобы некоторые значения не перезаписывали другие значения.В частности:
- A может быть перезаписан B, который может быть перезаписан C, который может быть перезаписан D, и так далее через F. Но B не может быть перезаписан A, а C не перезаписан посредствомB и т. Д.
- F, G или H могут перезаписывать любое значение, независимо от того, существует или нет существующее значение.
В псевдокоде это может выглядеть следующим образом:
if (rating >= F) {
insert;
} else if (rating > existing_rating) {
insert;
} else {
return;
}