Добавление логики в хранимую процедуру PostgreSQL - PullRequest
0 голосов
/ 21 декабря 2010

Я использую 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;
}

Ответы [ 3 ]

1 голос
/ 15 февраля 2011

Создать триггер ON перед вставкой или обновлением для этой таблицы.Для этого вы можете использовать свою функцию с небольшими изменениями, такими как изменение типа возвращаемого значения на TRIGGER.

Триггеры BEFORE запускаются перед вставкой строк в таблицы, поэтому вы можете проверить данные перед их записью.

Более подробную информацию о триггерах вы можете найти здесь:
http://www.postgresql.org/docs/9.0/interactive/plpgsql-trigger.html

0 голосов
/ 25 сентября 2012

Не можете ли вы что-то сделать с помощью оператора 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;
0 голосов
/ 25 сентября 2012

Способ выглядит так: CASE http://www.postgresql.org/docs/8.2/static/functions-conditional.html#AEN13066 не должно быть так сложно его реализовать.И как предложил @ szymon-guz, поместите его в триггер.

...