Как написать ограничение относительно максимального количества строк в postgresql? - PullRequest
19 голосов
/ 16 ноября 2009

Я думаю, что это довольно распространенная проблема.

У меня есть стол user(id INT ...) и стол photo(id BIGINT, owner INT). владельцем является ссылка на user(id).

Я бы хотел добавить к фотографии таблицы ограничение, которое препятствовало бы добавлению более 10 фотографий в базу данных для каждого пользователя.

Какой лучший способ написать это?

Thx!

Ответы [ 4 ]

24 голосов
/ 16 ноября 2009

Кассной прав; триггер будет лучшим способом для достижения этой цели.

Вот код:

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

Я включил блокировку таблицы, чтобы избежать ситуаций, когда две одновременные транзакции будут подсчитывать фотографии для пользователя, видеть, что текущий счетчик на 1 ниже предела, а затем обе вставки, что заставит вас переместиться на 1 сверх лимита. Если это вас не беспокоит, лучше снять блокировку, поскольку она может стать узким местом при большом количестве вставок / обновлений.

9 голосов
/ 16 ноября 2009

Вы не можете написать такое ограничение в объявлении таблицы.

Есть несколько обходных путей:

  • Создать триггер, который будет проверять количество фотографий для каждого пользователя
  • Создайте столбец photo_order, который будет сохранять порядок фотографий, введите (user_id, photo_order) UNIQUE и добавьте CHECK(photo_order BETWEEN 1 AND 10)
2 голосов
/ 16 ноября 2009

Другим подходом было бы добавить столбец «photo_count» в таблицу пользователей, обновить его с помощью триггеров, чтобы он отражал реальность, и добавить проверку для обеспечения максимального числа фотографий.

Дополнительным преимуществом этого является то, что в любой момент мы знаем (не считая), сколько фотографий у пользователя.

С другой стороны - предложенный Quassnoi подход также довольно крутой, так как дает вам возможность изменить порядок фотографий в случае, если пользователь захочет.

0 голосов
/ 14 сентября 2018

Лучшей альтернативой будет проверка количества строк при вставке:

insert into photos(id,owner) 
select 1,2 from dual
where (select count(*) from photos where id=1) < 10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...