он срабатывал перед вставкой записи в бд.
Я хочу, чтобы у меня констрейн не давал создавать дубликаты по двум конкретным полям и выбрасывал ошибку. Я использую CHECK constraint вместе с NOT VALID и вызываю функцию, которая проверяет моё условие unique_payment_title_constraint. Но когда я добавляю новую запись, она у меня сначала добавляется, а потом уже срабатывает функция на проверку, после добавления, которая выбрасывает исключение
```
ALTER TABLE payment_applications
ADD CONSTRAINT unique_name CHECK (
unique_payment_title_constraint(title, agent_nomenclature_id, contract_uuid)
) NOT VALID;
```
То есть, я внёс запись в таблицу, а потом функция выбросила исключение, потому что новая запись, которой раньше не было, теперь существует на момент проверки, после внесения уже
На триггерах это легко сделать, просто надо добавить триггер на BEFORE INSERT, и тогда оно будет работать как надо
Стоит ли эту проверку делать лучше на триггерах или на констрейнах?
лучше через логику делать, а не через базу (субъективно)
Констрейнты в БД, когда они применимы, почти всегда лучше проверок на клиенте БД, т.к. позволяют выполнить контроль целостности с минимальным оверхедом, в т.ч. не увеличивая времени блокировки записи. Чтобы получить те же гарантии со стороны клиента БД, вам придётся блокировать запись перед или в момент осуществления проверки и это, зачастую, будет отдельный запрос. С другой стороны, не всегда констрейнты удобны для анализа того, что не так, поэтому можно использовать двойную проверку: простую минимальную валидацию на клиенте БД без блокировки, но с отдачей развёрнутого ответа + констрейнт (при фейле которого возвращается системная ошибка, но вероятность этого небольшая)
1) unique лучшэ делать через unique или exclude. Многие проблемы решатся сами собой. 2) Мне сейчас лень проверять — но я бы скорее предположыл, что этот check не видит вообще записей, которые добавлены в том жэ запросе. Включая добавляемую. Как вы определили, что он выполняется "после"? Это точно? 3) В любом случае — обращаться к изменяемым частям БД в check крайне нерекомендуется. Если не получится через exclude — делайте на триггерах.
Как будто триггеры — это не логика...
Я как раз имел ввиду, то что вы сказали "простую минимальную валидацию на клиенте БД без блокировки, но с отдачей развёрнутого ответа + констрейнт". Я не сторонник сложной логики, которую нужно добавдять в БД (тригеры и другие вещи, так как их сложно отслеживать)
С триггерами есть другая проблема: не каждый разработчик напишет триггер корректно, который будет гарантировать заявленную консистентность данных. Системные триггеры, реализующие тот же foreign key, писали профессионалы и тестировались всем сообществом.
Согласен, триггеры специфичная вещь
Можно так alter table payment_applications add CONSTRAINT unique_name EXCLUDE (title WITH =, agent_nomenclature_id WITH =, contract_uuid with =); insert into payment_applications (title, agent_nomenclature_id, contract_uuid) values ('NAME1', 123::bigint, '123e4567-e89b-12d3-a456-426655440000'::uuid); insert into payment_applications (title, agent_nomenclature_id, contract_uuid) values ('NAME1', 123::bigint, '123e4567-e89b-12d3-a456-426655440000'::uuid); SQL Error [23P01]: ERROR: conflicting key value violates exclusion constraint "unique_name" Подробности: Key (title, agent_nomenclature_id, contract_uuid)=(NAME1, 123, 123e4567-e89b-12d3-a456-426655440000) conflicts with existing key (title, agent_nomenclature_id, contract_uuid)=(NAME1, 123, 123e4567-e89b-12d3-a456-426655440000).
Обсуждают сегодня