У меня есть таблица, которая в настоящее время имеет повторяющиеся значения в столбце.
Я не могу удалить эти ошибочные дубликаты, но хотел бы предотвратить добавление дополнительных неуникальных значений.
Могу ли я создать документ UNIQUE
, который не проверяет наличие соответствия?
Я пытался использовать, NOCHECK
но безуспешно.
В этом случае у меня есть таблица, которая связывает информацию о лицензировании с «CompanyName»
РЕДАКТИРОВАТЬ: наличие нескольких строк с одним и тем же «CompanyName» является неверными данными, но мы не можем удалить или обновить эти дубликаты в настоящее время. Один из подходов состоит в том, чтобы INSERT
использовать хранимую процедуру, которая не будет работать для дубликатов ... Если бы было возможно, чтобы SQL самостоятельно проверял уникальность, это было бы предпочтительнее.
Эти данные запрашиваются по названию компании. Для немногих существующих дубликатов это будет означать, что несколько строк возвращаются и отображаются ... Хотя это неправильно, это приемлемо в нашем случае использования. Цель состоит в том, чтобы предотвратить это в будущем. Из комментариев мне кажется, что я должен делать эту логику в хранимых процедурах.
Ответы:
Ответ "да". Вы можете сделать это с помощью отфильтрованного индекса (см. Документацию здесь ).
Например, вы можете сделать:
Это создает уникальный индекс, только на новый строк, а не для старых. Эта конкретная формулировка позволит дублировать с существующими значениями.
Если у вас есть всего несколько дубликатов, вы можете сделать что-то вроде:
источник
Да, вы можете сделать это.
Вот таблица с дубликатами:
Давайте проигнорируем существующие и убедимся, что новые дубликаты не могут быть добавлены:
Давайте проверим это решение:
источник
UNIQUE
ограничение в столбце, допускающем значение NULL, гарантирует, что существует не более одногоNULL
значения. Стандарт SQL (и почти все другие СУБД SQL) говорит, что он должен разрешать любое количествоNULL
значений (т. Е. Ограничение должно игнорировать нулевые значения).Отфильтрованный уникальный индекс - блестящая идея, но он имеет небольшой недостаток - независимо от того, используете ли вы
WHERE identity_column > <current value>
условие илиWHERE identity_column NOT IN (<list of ids for duplicate values here>)
.При первом подходе вы все равно сможете вставлять дубликаты данных в будущем, дубликаты существующих (сейчас) данных. Например, если у вас есть (даже только одна) строка с
CompanyName = 'Software Inc.'
индексом, индекс не будет запрещать вставку еще одной строки с таким же названием компании. Это только запретит, если вы попробуете дважды.Со вторым подходом есть улучшение, вышеупомянутое не будет работать (что хорошо.) Однако вы все равно сможете вставить больше дубликатов или существующих дубликатов. Например, если у вас есть (две или более) строки теперь с
CompanyName = 'DoubleData Co.'
индексом, индекс не будет запрещать вставку еще одной строки с таким же названием компании. Это только запретит, если вы попробуете дважды.(Обновление) Это можно исправить, если для каждого дублированного имени вы исключаете из списка исключений один идентификатор. Если, как и в приведенном выше примере, имеется 4 строки с дубликатами
CompanyName = DoubleData Co.
и идентификаторами4,6,8,9
, в списке исключений должно быть только 3 из этих идентификаторов.При втором подходе еще одним недостатком является громоздкое условие (насколько громоздким оно зависит от того, сколько дубликатов существует в первую очередь), поскольку SQL-Server, похоже, не поддерживает
NOT IN
оператор вWHERE
части отфильтрованных индексов. Смотрите SQL-Fiddle . Вместо этого уWHERE (CompanyID NOT IN (3,7,4,6,8,9))
вас должно быть что-то вроде того,WHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
что я не уверен, есть ли последствия для эффективности с таким условием, если у вас есть сотни повторяющихся имен.Другое решение (похожее на @Alex Kuznetsov's) заключается в добавлении еще одного столбца, заполнении его номерами рангов и добавлении уникального индекса, включающего этот столбец:
Затем вставка строки с повторяющимся именем завершится неудачно из-за
DEFAULT 1
свойства и уникального индекса. Это все еще не на 100% надежно (в то время как у Алекса). Дубликаты по-прежнему будут добавляться, еслиRn
вINSERT
операторе явно указано значение илиRn
значения были злонамеренно обновлены.SQL-Fiddle-2
источник
Другой альтернативой является написание скалярной функции, которая проверяет, существует ли уже значение в таблице, а затем вызывает эту функцию из проверочного ограничения.
Это будет делать ужасные вещи для производительности.
источник
Я ищу то же самое - создаю ненадежный уникальный индекс, чтобы игнорировать существующие неверные данные, но новые записи не могут быть дубликатами того, что уже существует.
При чтении этой темы мне приходит в голову, что лучшим решением является написание триггера, который будет проверять [вставлено] в родительской таблице наличие дубликатов, и, если между этими таблицами есть дубликаты, ROLLBACK TRAN.
источник