Например, с таблицей, подобной этой:
create table foo(bar int identity, chk char(1) check (chk in('Y', 'N')));
Не имеет значения, реализован ли флаг как a char(1)
, a bit
или как угодно. Я просто хочу иметь возможность применять ограничение, которое может быть установлено только в одной строке.
constraint
database-agnostic
referential-integrity
Джек Дуглас
источник
источник
Ответы:
SQL Server 2008 - отфильтрованный уникальный индекс
источник
SQL Server 2000, 2005:
Вы можете воспользоваться тем, что в уникальном индексе допускается только один нуль:
для 2000, вам может понадобиться
SET ARITHABORT ON
(спасибо @gbn за эту информацию)источник
Oracle:
Поскольку Oracle не индексирует записи, в которых все проиндексированные столбцы равны нулю, вы можете использовать уникальный индекс на основе функций:
Этот индекс будет индексировать только одну строку максимум.
Зная этот факт, вы также можете реализовать битовый столбец немного иначе:
Здесь возможные значения для столбца
chk
будутY
иNULL
. Только одна строка может иметь значениеY.
источник
not null
ограничение?not null
ограничение, если не хотите иметь значения NULL (это не было понятно из спецификации вопроса). В любом случае только одна строка может иметь значение «Y».default
)?Y
либоnull
, смотрите мое обновление.null
s - возможно, за счет некоторой ясностиЯ думаю, что это случай правильного структурирования таблиц вашей базы данных. Чтобы сделать его более конкретным, если у вас есть человек с несколькими адресами, и вы хотите, чтобы он был по умолчанию, я думаю, вам следует сохранить addressID адреса по умолчанию в таблице person, а не иметь столбец по умолчанию в таблице адресов:
Вы можете сделать DefaultAddressID обнуляемым, но таким образом структура обеспечивает соблюдение вашего ограничения.
источник
MySQL:
Проверочные ограничения игнорируются в MySQL , поэтому мы должны рассматривать
null
илиfalse
как ложные иtrue
истинные. Максимум 1 строка может иметьchk=true
Вы можете считать это улучшение , чтобы добавить триггер изменения
false
вtrue
на вставки / обновления в качестве обходного для отсутствия проверки ограничения - ИМО это не улучшение , хотя.Я надеялся, что смогу использовать char (0), потому что это
К сожалению, с MyISAM и InnoDB по крайней мере, я получаю
--редактировать
В конце концов, это не очень хорошее решение, поскольку в MySQL
boolean
это синонимtinyint(1)
, и поэтому допускает ненулевые значения, отличные от 0 или 1. Возможно, этоbit
был бы лучший выбор.источник
null
, чтоfalse
,true
- я действительно задаюсь вопросом, есть ли что-то более аккуратное ...SQL Server:
Как это сделать:
Лучший способ - фильтрованный индекс. Использует DRI
SQL Server 2008+
Вычисляем столбец с уникальностью. Использует DRI
Смотрите ответ Джека Дугласа. SQL Server 2005 и ранее
Индексированное / материализованное представление, похожее на отфильтрованный индекс. Использует DRI
Все версии.
Курок. Использует код, а не DRI.
Все версии
Как не сделать это:
Смотреть один два три четыре
источник
PostgreSQL:
--редактировать
или (намного лучше) используйте уникальный частичный индекс :
источник
Такая проблема является еще одной причиной, почему я задал этот вопрос:
Настройки приложения в базе данных
Если у вас есть таблица настроек приложения в вашей базе данных, у вас может быть запись, которая будет ссылаться на идентификатор одной записи, которую вы хотите считать «особой». Затем вы просто посмотрите, какой идентификатор у вашей таблицы настроек, и вам не понадобится целый столбец для установки только одного элемента.
источник
Возможные подходы с использованием широко применяемых технологий:
1) Отменить привилегии «писателя» на столе. Создайте процедуры CRUD, обеспечивающие применение ограничения на границах транзакции.
2) 6NF: опустить
CHAR(1)
столбец. Добавьте таблицу ссылок, ограниченную, чтобы гарантировать, что ее количество элементов не может превышать единицу:Измените семантику приложения так, чтобы рассматриваемым «по умолчанию» была строка в новой таблице. Возможно использовать представления для инкапсуляции этой логики.
3) Оставьте
CHAR(1)
колонку. Добавьтеseq
целочисленный столбец. Установите уникальное ограничениеseq
. Измените семантику приложения так, чтобы рассматриваемое «значение по умолчанию» представляло собой строку, в которойseq
значение равно единице, либоseq
значение наибольшее / наименьшее значение или аналогичное. Возможно использовать представления для инкапсуляции этой логики.источник
Для тех, кто использует MySQL, есть подходящая хранимая процедура:
Чтобы убедиться, что ваша таблица чистая и хранимая процедура работает, предполагая, что ID 200 является значением по умолчанию, выполните следующие действия:
Вот триггер, который также помогает:
Чтобы убедиться, что ваша таблица чистая и триггер работает, предполагая, что ID 200 является значением по умолчанию, выполните следующие действия:
Попробуйте!
источник
В SQL Server 2000 и более поздних версиях вы можете использовать индексированные представления для реализации сложных (или многостоловых) ограничений, подобных тем, которые вы запрашиваете.
Также Oracle имеет аналогичную реализацию для материализованных представлений с отложенными проверочными ограничениями.
Смотрите мой пост здесь .
источник
Стандартный переходный SQL-92, широко применяемый, например, SQL Server 2000 и выше:
Отзовите привилегии «писателя» из таблицы. Создайте два представления для
WHERE chk = 'Y'
иWHERE chk = 'N'
соответственно, в том числеWITH CHECK OPTION
. ДляWHERE chk = 'Y'
представления включите условие поиска, чтобы его мощность не превышала единицу. Предоставьте «писательские» привилегии на представления.Пример кода для просмотров:
источник
Вот решение для MySQL и MariaDB с использованием виртуальных столбцов, которое немного элегантнее. Требуется MySQL> = 5.7.6 или MariaDB> = 5.2:
Создайте виртуальный столбец со значением NULL, если вы не хотите применять ограничение Unique:
(Для MySQL используйте
STORED
вместоPERSISTENT
.)источник
Стандарт FULL SQL-92: использовать подзапрос в
CHECK
ограничении, который не реализован широко, например поддерживается в Access2000 (ACE2007, Jet 4.0 и т. Д.) И выше в режиме запросов ANSI-92 .Пример кода: примечание
CHECK
ограничения в Access всегда на уровне таблицы. Поскольку вCREATE TABLE
утверждении в вопросе используетсяCHECK
ограничение на уровне строк , его необходимо слегка изменить, добавив запятую:источник
Я только просмотрел ответы, поэтому мог пропустить подобный ответ. Идея состоит в том, чтобы использовать сгенерированный столбец, который является либо ПК, либо константой, которая не существует в качестве значения для ПК.
AFAIK это действительно в SQL2003 (так как вы искали агностическое решение). DB2 допускает это, не уверенный, сколько других поставщиков, которые принимают это.
источник