Используя Oracle, если значение столбца может быть «ДА» или «НЕТ», можно ли ограничить таблицу так, чтобы только одна строка могла иметь значение «ДА»?
Я бы предпочел изменить структуру таблицы, но это невозможно.
[UDPATE] К сожалению, в этой таблице недопустимы нулевые значения.





Это не работает с определением таблицы.
Однако, если вы обновляете таблицу с помощью триггера, вызывающего хранимую процедуру, вы можете убедиться, что только одна строка содержит «YES».
-1 для решения на основе триггера. Они никогда не работают для обеспечения ограничений на уровне таблицы.
Это глупый прием, но если столбец допускает NULL, вы можете использовать NULL вместо «NO» и использовать «YES», как и раньше. Примените ограничение уникального ключа к этому столбцу, и вы никогда не получите два значения «ДА», но все равно у вас будет много «НЕТ».
Обновление: @Nick Pierpoint: предложил добавить ограничение проверки, чтобы значения столбца были ограничены только «YES» и NULL. В его ответе весь синтаксис продуман.
Ничего лишнего - это правильный путь. +1
Вам также нужно будет добавить в таблицу ограничение проверки, чтобы она не разрешала ничего, кроме «YES» или null.
если вы хотите, чтобы он выглядел красиво, вы, вероятно, также могли бы обернуть представление NVL вокруг него, тогда вы получите свой Y / N
Ну, использовать NULL сложно, если вы хотите присоединиться к нему. Возможно, это стоит сделать, но это все же компромисс в дизайне от более правильного подхода.
Поддерживает ли Oracle что-то вроде отфильтрованные индексы (на прошлой неделе я слышал об этом, например, MSSQL2008)? Возможно, вы можете определить уникальный ключ, который применяется только к строкам со значением «Да» в вашем столбце.
Никаких фильтрованных индексов, но ФБР предлагают более гибкий (хотя, возможно, менее сжатый) способ сделать то же самое.
Используйте функциональный индекс:
create unique index only_one_yes on mytable
(case when col='YES' then 'YES' end);
Oracle индексирует только те ключи, которые не являются полностью нулевыми, и выражение CASE здесь гарантирует, что все значения «NO» будут изменены на нулевые и, следовательно, не будут индексированы.
Думаю, я бы использовал вторую таблицу, чтобы указать на соответствующую строку в вашей текущей таблице. Эта другая таблица также может использоваться для хранения значений других переменных.
трудно поддерживать в стабильной среде
Следуя моему комментарию к предыдущему ответу yukondude, я бы добавил уникальный индекс и ограничение проверки:
create table mytest (
yesorno varchar2(3 char)
);
create unique index uk_mytest_yesorno on mytest(yesorno);
alter table mytest add constraint ck_mytest_yesorno check (yesorno is null or yesorno = 'YES');
Я думаю, что до тех пор, пока NULL подходит в качестве значения «не да», этот метод имеет преимущество перед методом FBI, потому что ограничения могут, по крайней мере, использоваться оптимизатором. Я думаю, что запросы с предикатами yesorno = 'YES' и yesorno is null будут получать более точные оценки мощности.
Поскольку всегда будет только одна строка с «YES» и каждая другая строка с нулевым значением, тогда вы получите индекс, используемый для поиска строки «YES», и полное сканирование (совершенно справедливо), чтобы получить все остальное ( "НЕТ").
Конечно - вопрос лишь в том, является ли замена «Нет» на Null стоящим компромиссом для достижения этой цели.
Вы захотите проверить статью Тома Кайта, в которой задается именно этот вопрос и его ответ:
http://tkyte.blogspot.com/2008/05/another-of-day.html
Резюме: не используйте триггеры, не используйте автономные транзакции, используйте две таблицы.
Если вы используете базу данных Oracle, вы ДОЛЖНЫ познакомиться с AskTom и получить его книги.
Заданный вопрос немного отличается от этого, в вопросе Тома в таблице может быть несколько «Y», но только по одному на страну. Как я читал, в этом примере в таблице может быть только 1 Да, и в этом случае индексное решение, похоже, работает. Но да, AskTom необходим для базы данных Oracle.
Я согласен. Если бы Тому задали этот вопрос, я бы предположил, что он определенно выбрал бы индексное решение.
О боже, нули не разрешены - это немного меняет ситуацию - теперь вам нужно использовать индекс на основе функций (@Tony Andrews). По-прежнему избегайте триггеров и автономных транзакций.