向 PostgreSQL 存储过程添加逻辑

发布于 2024-10-08 23:04:10 字数 1850 浏览 0 评论 0原文

我正在使用 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-structs.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 覆盖,B 可以被 C 覆盖,C 可以被 D 覆盖,以此类推,通过 F。但是 B 不能被 A 覆盖,C 也不能被 B 覆盖,等等。
  • F、G 或H 可以覆盖任何值,无论现有值是更低还是更高。

在伪代码中,这可能看起来像:

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

I'm using PostgreSQL (8.3+) and have defined an enum and a table as follows:

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

I've also created a stored procedure to upsert new rows into the preferences table, using the example from
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;

I need to add some additional logic to the upsert to prevent some values from overwriting other values. Specifically:

  • A can be overwritten by B, which can by overwritten by C, which can be overwritten by D, and so on through F. But B cannot by overwritten by A, nor C overwritten by B, etc.
  • F, G, or H can overwrite any value, regardless if an existing value is lower or higher.

In pseudocode, this might look like:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

请止步禁区 2024-10-15 23:04:10

在此表上创建一个 ON BEFORE INSERT OR UPDATE 触发器。为此,您可以使用您的函数,进行一些小的更改,例如将返回类型更改为 TRIGGER。

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

有关触发器的更多信息,您可以在这里找到:
http://www.postgresql.org/docs/9.0/interactive/plpgsql -trigger.html

Create a trigger ON BEFORE INSERT OR UPDATE on this table. For that you could use your function, with small changes like changing the return type to TRIGGER.

The BEFORE triggers are fired before inserting rows into tables, so you can check the data before writing them.

More information on triggers you can find here:
http://www.postgresql.org/docs/9.0/interactive/plpgsql-trigger.html

看春风乍起 2024-10-15 23:04:10

查看方法是 CASE http: //www.postgresql.org/docs/8.2/static/functions-conditional.html#AEN13066 实现它应该不会那么困难。正如 @szymon-guz 建议的那样,将其放入触发器中。

The way to look is CASE http://www.postgresql.org/docs/8.2/static/functions-conditional.html#AEN13066 it shouldn't be so difficult to implement it. And as @szymon-guz suggested, place it in trigger.

情栀口红 2024-10-15 23:04:10

你不能用案例陈述做点什么吗?

像这样的东西。

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

Can't you do something with a case statement?

Something like this.

--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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文