如何在postgresql中写一个关于最大行数的约束?

问题描述 投票:19回答:4

我认为这是一个非常普遍的问题。

我有一张桌子user(id INT ...)和一张桌子photo(id BIGINT, owner INT)。所有者是user(id)的参考。

我想在桌面照片中添加一个约束,这样可以防止让每个用户输入10张照片进入数据库。

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

谢谢!

sql postgresql constraints
4个回答
24
投票

Quassnoi是对的;触发器是实现这一目标的最佳方式。

这是代码:

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

我包括表锁定,以避免两个并发的tansactions为用户计算照片的情况,看到当前计数低于限制1,然后插入,这将导致你超过限制1。如果您不关心这一点,最好删除锁定,因为它可能成为许多插入/更新的瓶颈。


9
投票

您不能在表声明中编写这样的约束。

有一些解决方法:

  • 创建一个触发器,用于检查每个用户的照片数量
  • 创建一个photo_order列,保持照片的顺序,使(user_id, photo_order) UNIQUE,并添加CHECK(photo_order BETWEEN 1 AND 10)

2
投票

另一种方法是将“photo_count”列添加到users表,使用触发器更新它以使其反映现实,并添加检查以强制执行最大数量的照片。

这样做的另一个好处是,在任何特定时刻,我们都知道(不计算)用户拥有的照片数量。

另一方面 - Quassnoi建议的方法也非常酷,因为它使您能够在用户需要的情况下重新排序照片。


0
投票

更好的选择是在执行插入时检查行数:

insert into photos(id,owner) 
select 1,2 from dual
where (select count(*) from photos where id=1) < 10
© www.soinside.com 2019 - 2024. All rights reserved.