Обычно вы, вероятно, пытаетесь сделать внешний ключ (в исходной таблице) обнуляемым и наложить на него уникальное ограничение.
Тот факт, что он может иметь значение NULL, означает, что вы можете иметь нулевую запись в исходной таблице, которая не ссылается на запись в целевой таблице. И, если оно не равно нулю, уникальное ограничение гарантирует, что только одна строка исходной таблицы может ссылаться на строку в целевой таблице.
К сожалению, по крайней мере, для SQL Server (a) значения NULL в столбцах с уникальными ограничениями также должны быть уникальными, хотя это «нарушает» рекомендацию SQL о том, что NULL не равно никакому значению, включая еще один NULL. Так что в основном этот метод не будет работать с SQL Server.
Одним из возможных путей выхода из этого затруднительного положения (b) является ограничение внешнего ключа со столбцом, допускающим значение NULL, но нет уникальное ограничение. Это позволит вам либо вообще не ссылаться на строку в целевой таблице (NULL в исходной таблице), либо ссылаться на целевую строку (любое значение, отличное от NULL в исходной таблице).
Однако это не дает вам требования «только одна исходная строка может ссылаться на целевую строку». Это можно добавить с помощью триггера before- (insert / update), который будет проверять каждую вторую строку в исходной таблице, чтобы убедиться, что никакая другая строка уже не ссылается на целевую строку.
И вы должны почти всегда отдавать предпочтение ограничениям в самой базе данных. Вы никогда не знаете, когда мошенническое приложение (злокачественное или ошибочное) подключится к вашей базе данных и решит не следовать правилам.
(a) Следующий текст, перефразированный с здесь , показывает различную поддержку обнуляемых уникальных столбцов в нескольких продуктах СУБД:
Стандарт:
Как указывает имя ограничения, столбец (столбцы) с ограничением UNIQUE может содержать только уникальные (комбинации) значений.
Столбец или набор столбцов, на которые распространяется ограничение UNIQUE, также должны быть подвержены ограничению NOT NULL, если только СУБД не реализует необязательную функцию «NULLs позволен» (идентификатор функции 591). Дополнительная функция добавляет некоторые дополнительные характеристики к ограничению UNIQUE:
Во-первых, столбцы, включенные в ограничение UNIQUE, могут также иметь ограничения NOT NULL, но они не обязаны это делать. Во-вторых, если столбцы с ограничениями UNIQUE также не имеют ограничений NOT NULL, то столбцы могут содержать любое количество значений NULL (логическое следствие того факта, что NULL не равен NULL).
PostgreSQL:
Соответствует стандарту, включая дополнительную разрешенную функцию NULL.
DB2:
Следует за необязательными частями UNIQUE-ограничения. Не реализует дополнительную разрешенную функцию NULL.
MSSQL:
Следует стандарту с изюминкой.
MSSQL предлагает функцию разрешенных значений NULL, но допускает не более одного экземпляра значения NULL, если допустимы NULL. Другими словами, он нарушает характеристику 2 в приведенном выше описании стандарта.
MySQL:
Соответствует стандарту, включая дополнительную разрешенную функцию NULL.
Oracle:
Следует стандарту с изюминкой относительно многоколоночных UNIQUE-ограничений.
Реализована необязательная функция разрешенных значений NULL: если UNIQUE-ограничение накладывается на один столбец, то этот столбец может содержать любое количество NULL (как ожидается из характеристики 2 в приведенном выше описании стандарта). Однако если UNIQUE-ограничение указано для нескольких столбцов, то Oracle видит ограничение как нарушенное, если любые две строки
- содержит как минимум один NULL в столбце, на который влияет ограничение
- идентичные значения, отличные от NULL, в остальных столбцах, на которые распространяется ограничение
(b) Другим выходом, конечно, является выбор СУБД, реализующей эту функцию, например PostgreSQL или MySQL.
Это может оказаться невозможным в вашем конкретном случаено это должно быть, по крайней мере, . Например, я держусь подальше от Oracle из-за его неспособности различать NULL из пустых строк в определенных символьных столбцах, хотя другие, вероятно, не как "пурист" (моя женасказал бы "анальный retentive"), как я: -)