我认为这是一个相当普遍的问题.

我有一张user(id INT ...)号桌和一张photo(id BIGINT, owner INT)号桌.所有者是user(id)上的推荐人.

我想给表photo添加一个约束,防止每个用户有超过10张照片进入数据库.

写这个最好的方式是什么?

谢谢!

推荐答案

卡西诺是对的;触发是实现这一目标的最佳方式.

以下是代码:

CREATE OR REPLACE FUNCTION enforce_photo_count() RETURNS trigger AS $$
DECLARE
    max_photo_count INTEGER := 10;
    photo_count INTEGER := 0;
    must_check BOOLEAN := false;
BEGIN
    IF TG_OP = 'INSERT' THEN
        must_check := true;
    END IF;

    IF TG_OP = 'UPDATE' THEN
        IF (NEW.owner != OLD.owner) THEN
            must_check := true;
        END IF;
    END IF;

    IF must_check THEN
        -- prevent concurrent inserts from multiple transactions
        LOCK TABLE photos IN EXCLUSIVE MODE;

        SELECT INTO photo_count COUNT(*) 
        FROM photos 
        WHERE owner = NEW.owner;

        IF photo_count >= max_photo_count THEN
            RAISE EXCEPTION 'Cannot insert more than % photos for each user.', max_photo_count;
        END IF;
    END IF;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;


CREATE TRIGGER enforce_photo_count 
    BEFORE INSERT OR UPDATE ON photos
    FOR EACH ROW EXECUTE PROCEDURE enforce_photo_count();

我加入了表锁定,以避免出现两个并发的tansaction会为一个用户计算照片数的情况,看到当前的计数低于限制1,然后两个都插入,这会导致您超过限制1.如果您不担心这一点,那么最好移除锁定,因为它可能会成为许多插入/更新的瓶颈.

Postgresql相关问答推荐

Haskell仆人发布FormUrlEncode for(向量字符串)字段

在Axum 0.5中,如何在一个请求处理程序中同时使用数据库和路径解析?

Postgres:创建分区需要很长时间

我可以将jsonb_set与来自SELECT语句的新值(第三个参数)一起使用吗?

安装age-installation时出错

Postgres 低估了导致错误查询计划的行数

查找列中的数据是否满足sql中的数据类型条件

Psycopg2 在大型 Select 查询中耗尽内存

UPDATE implies move across partitions

更详细地解释 JOIN 与 LEFT JOIN 和 WHERE 条件性能建议

需要将整个 postgreSQL 数据库加载到 RAM 中

'active' 标志与否?

如何在 PostgreSQL 触发器函数中获取表名?

使用 postgres regexp_replace 将字符串列表替换为始终相同的字符串

为什么PostgresQL查询性能随时间下降,但在重建索引时恢复

Postgres 中是否有 MAX_INT 常量?

PostgreSQL:如何在用户级别设置 search_path?

如何为 Postgres psql 设置时区?

使用 Homebrew 安装 icu4c 版本 63

Capistrano 与 PostgreSQL,错误:database is being accessed by other users