Postgresql: Умовно унікальне обмеження


116

Я хотів би додати обмеження, яке застосовує унікальність для стовпця лише в частині таблиці.

ALTER TABLE stop ADD CONSTRAINT myc UNIQUE (col_a) WHERE (col_b is null);

WHEREЧастина вище видавати бажане за дійсне.

Будь-який спосіб зробити це? Або я повинен повернутися до реляційної дошки для малювання?


2
Зазвичай робиться. Дивіться "Частковий унікальний індекс"
Крейг Рінгер

11
@yvesonline ні, це звичайне унікальне обмеження. Плакат хоче часткового унікального обмеження.
Крейг Рінгер

Відповіді:


186

PostgreSQL не визначає часткового (тобто умовного) UNIQUEобмеження - однак, ви можете створити частковий унікальний індекс . PostgreSQL використовує унікальні індекси для реалізації унікальних обмежень, тому ефект такий же, ви просто не побачите обмеження, вказане в information_schema.

CREATE UNIQUE INDEX stop_myc ON stop (col_a) WHERE (col_b is NOT null);

Дивіться часткові індекси .


24
Супер! Неінтуїтивно, що "обмеження" не проявляється як обмеження, але, тим не менш, дає бажану помилкуERROR: duplicate key value violates unique constraint "stop_myc"
EoghanM

7
Варто зазначити, що це не дозволить створити референси FKs, що частково унікальне поле.
ffflabs

11
Також варто зазначити, що цей показник не може бути відкладений. Якщо вам потрібно здійснити масове оновлення, це може спричинити проблему, оскільки унікальність перевіряється після кожного рядка, а не після заяви, як це було б для обмеження, або після транзакції, як це було б для відкладеного обмеження.
sage88

37

вже було сказано, що PG не визначає часткового (тобто умовного) UNIQUE обмеження. Також документація говорить, що кращим способом додати унікальне обмеження до таблиці є ADD CONSTRAINT Унікальні індекси

Кращим способом додати до таблиці унікальне обмеження є ALTER TABLE ... ADD CONSTRAINT. Використання індексів для забезпечення унікальних обмежень може вважатися деталізацією реалізації, до якої не слід звертатися безпосередньо. Однак слід пам’ятати, що немає потреби вручну створювати індекси на унікальних стовпцях; це може просто дублювати автоматично створений індекс.

Існує спосіб реалізувати це за допомогою обмежень виключення (спасибі @dukelion за це рішення)

У вашому випадку це буде виглядати так

ALTER TABLE stop ADD CONSTRAINT myc EXCLUDE (col_a WITH =) WHERE (col_b IS null);

при такому підході ви не використовуєте "використання" для визначення методу індексу, так що це може бути надзвичайно повільним або постгреси створюють індекс за замовчуванням для цього? Цей метод є канонічним вибором, але не завжди кращим вибором! Я думаю, вам знадобиться пункт "використання" з індексом, щоб зробити цей вибір кращим.
Натан Медейрос

10
У той час як повільніше, перевагою рішення виключення є те, що воно відкладається (і за замовчуванням відкладається до кінця оператора). Навпаки, прийняте унікальне рішення індексу не може бути відкладено (і перевіряється після кожної зміни рядків). Таким чином, масове оновлення часто неможливе, оскільки кроки під час оновлення порушуватимуть унікальне обмеження, навіть якщо воно не було б порушено в кінці оператора оновлення атома.
sage88

1
Ця примітка була видалена з документів у серпні 2015 року
Раніз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.