Перевірте обмеження лише один з трьох стовпців не є нульовим


61

У мене є таблиця (SQL Server), яка містить 3 типи результатів: FLOAT, NVARCHAR (30) або DATETIME (3 окремі колонки). Я хочу переконатися, що для будь-якого заданого рядка лише один стовпець має результат, а інші стовпці - NULL. Яке найпростіше обмеження перевірки для досягнення цього?

У контексті цього намагається вдосконалити можливість фіксувати нечислові результати у існуючу систему. Додавання до таблиці двох нових стовпців з обмеженням для запобігання більш ніж одному результату в рядку було найбільш економічним підходом, не обов'язково правильним.

Оновлення: Вибачте, тип даних snafu. На жаль, я не мав наміру вказані типи результатів інтерпретувати як типи даних SQL Server, просто загальні терміни, виправлені зараз.

Відповіді:


72

Слід виконати трюк:

CREATE TABLE MyTable (col1 FLOAT NULL, col2 NVARCHAR(30) NULL, col3 DATETIME NULL);
GO

ALTER TABLE MyTable
ADD CONSTRAINT CheckOnlyOneColumnIsNull
CHECK 
(
    ( CASE WHEN col1 IS NULL THEN 0 ELSE 1 END
    + CASE WHEN col2 IS NULL THEN 0 ELSE 1 END
    + CASE WHEN col3 IS NULL THEN 0 ELSE 1 END
    ) = 1
)
GO

24

Можливо, вам доведеться зробити три тести в рамках обмеження, один тест для кожної пари, який ви хочете бути нульовим, і один для стовпця, який не повинен бути нульовим:

ALTER TABLE table
ADD CONSTRAINT CK_one_is_null
CHECK (
     (col1 IS NOT NULL AND col2 IS NULL AND col3 IS NULL)
  OR (col2 IS NOT NULL AND col1 IS NULL AND col3 IS NULL) 
  OR (col3 IS NOT NULL AND col1 IS NULL AND col2 IS NULL)
);

Це не так масштабно, у мене є таблиця з 9 зовнішніми ключами, і лише один не повинен бути недійсним, я вважаю за краще рішення
@MarkStoreySmith

5

Ось рішення PostgreSQL з використанням вбудованих функцій масиву :

ALTER TABLE your_table
ADD chk_only_one_is_not_null CHECK (array_length(array_remove(ARRAY[col1::text, col2::text, col3::text], NULL), 1) = 1);

Чи буде це швидшою реалізацією в postgreSQL, ніж згадані раніше рішення CASE або AND / OR, розміщені відповідно Марк Сторі та mrdenny?
Кріс Бріт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.