PostgreSQL 9.0 и более поздние версии
В PostgreSQL 9.0 добавлено отложенные уникальные ограничения , что является именно той функцией, которая вам, кажется, нужна.Таким образом, уникальность проверяется во время фиксации, а не во время обновления.
Создайте ограничение UNIQUE с ключевым словом DEFERRABLE:
ALTER TABLE foo ADD CONSTRAINT foo_uniq (foo_id) DEFERRABLE;
Позже, перед выполнением оператора UPDATE, вы запускаетев той же транзакции:
SET CONSTRAINTS foo_uniq DEFERRED;
В качестве альтернативы вы можете создать ограничение с ключевым словом INITIALLY DEFERRED
для самого уникального ограничения, поэтому вам не нужно запускать SET CONSTRAINTS
- но это может повлиять напроизводительность других ваших запросов, которым не нужно откладывать ограничение.
PostgreSQL 8.4 и старше
Если вы хотите использовать уникальное ограничение только для гарантии уникальности - не в качестве целидля внешнего ключа - тогда этот обходной путь может помочь:
Сначала добавьте в таблицу логический столбец, например is_temporary
, который временно различает обновленные и не обновленные строки:
CREATE TABLE foo (value int not null, is_temporary bool not null default false);
Затем создайте частичный уникальный индекс , который влияет только на строки, где is_teven = false:
CREATE UNIQUE INDEX ON foo (value) WHERE is_temporary=false;
Теперь каждый раз, когда вы делаете обновления, которые вы удалилиВ действительности, вы запускаете их в два этапа:
UPDATE foo SET is_temporary=true, value=value+1 WHERE value>3;
UPDATE foo SET is_temporary=false WHERE is_temporary=true;
Пока эти операторы выполняются в одной транзакции, это будет абсолютно безопасно - другие сеансы никогда не будут видеть временные строки.Недостатком является то, что вы будете писать строки дважды.
Обратите внимание, что это просто уникальный индекс, а не ограничение , но на практике это не должно иметь значения.