Объединение UNIQUE и CHECK ограничений - PullRequest
4 голосов
/ 06 апреля 2010

У меня есть таблица со столбцами ab и c, и если c равно false, я хочу разрешить вставки только в том случае, если столбцы a и b уникальны, но если c равно true, тогда a и b не обязательно должны быть уникальными. 1001 *

Пример: В таблице может быть только один (foo, bar, false), но не может быть ограничений на количество (foo, bar, true).

Я пробовал что-то вроде CONSTRAINT blah UNIQUE (a, b) и CHECK (C - TRUE), но я не могу понять правильный синтаксис.

Ответы [ 4 ]

9 голосов
/ 06 апреля 2010
  1. Создайте индексированное представление, возвращающее a и b с фильтром WHERE C = false, затем создайте уникальный индекс для представления. Это общий подход

  2. Если у вас SQL Server 2008, тогда создает уникальный отфильтрованный индекс вместо

  3. Хранимая процедура

  4. Триггер (до или после)

5 голосов
/ 06 апреля 2010

Уникальные ограничения для всех строк, и нет способа указать только некоторые строки.

Проверочные ограничения предназначены только для проверки в пределах одной строки.

Единственный способ выполнить ваши требования - это выполнить одно из следующих действий:

1) создать хранимую процедуру, из которой сделаны все ВСТАВКИ. Вы можете проверить всю свою логику здесь. Тем не менее, мошеннические программы / пользователи могут избежать этого и победить вашу логику.

2) создайте триггер, который проверяет вашу логику и вызывает сбой неверных вставок / обновлений. Должен быть написан для обработки набора строк одновременно

3) создайте проверочное ограничение, которое вызывает пользовательскую функцию, которая выполняет проверки вашей проверки. Это считается плохой практикой, и ее следует избегать, поскольку они очень медленные и могут не работать при многострочных обновлениях.

Я рекомендую вариант №2, триггер, потому что это именно то, для чего были разработаны триггеры.

1 голос
/ 06 апреля 2010

Вы всегда можете создать триггер, который проверяет необходимые условия перед вставкой.

0 голосов
/ 07 апреля 2010

Вы можете использовать табличное ограничение (в зависимости от движка SQL - неясно, какой из них вы используете), чтобы убедиться, что не слишком много кортежей определенного типа.

Под Firebird 2.1:

fb> CREATE TABLE so2587151 (
  >   a VARCHAR(16) NOT NULL,
  >   b VARCHAR(16) NOT NULL,
  >   c VARCHAR(1) NOT NULL CHECK (c in ('T', 'F')),
  >   CONSTRAINT so2587151_only_one_false CHECK (    -- begin CONSTRAINT
  >     NOT EXISTS (   SELECT a, b, COUNT('x')
  >                      FROM so2587151
  >                     WHERE c = 'F'
  >                  GROUP BY 1, 2
  >                    HAVING COUNT('x') >= 1  )
  >   )                                              -- end CONSTRAINT
  > );
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'T');
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'T');
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'F');
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'F');
Error: Operation violates CHECK constraint  on view or table
-Operation violates CHECK constraint SO2587151_ONLY_ONE_FALSE on view or table SO2587151
-At trigger 'CHECK_15'
fb> SELECT * FROM so2587151;
 A  |  B  | C
==============
foo | bar | T
foo | bar | T
foo | bar | F

Как видно из сообщения об ошибке нарушения ограничения, это реализовано в терминах механизмов запуска Firebird под капотом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...