Mam tabelę, która ma obecnie zduplikowane wartości w kolumnie.
Nie mogę usunąć tych błędnych duplikatów, ale chciałbym zapobiec dodawaniu dodatkowych, nieunikalnych wartości.
Czy mogę utworzyć taki UNIQUE
, który nie sprawdza istniejącej zgodności?
Próbowałem użyć, NOCHECK
ale nie powiodło się.
W tym przypadku mam tabelę, która wiąże informacje licencyjne z „CompanyName”
EDYCJA: Posiadanie wielu wierszy z tym samym „CompanyName” to złe dane, ale w tej chwili nie możemy usunąć ani zaktualizować tych duplikatów. Jednym z podejść jest INSERT
użycie procedury składowanej, która zakończy się niepowodzeniem w przypadku duplikatów ... Gdyby możliwe było samodzielne sprawdzenie unikalności przez SQL, byłoby to preferowane.
Dane te są wyszukiwane według nazwy firmy. W przypadku kilku istniejących duplikatów oznacza to, że wiele wierszy jest zwracanych i wyświetlanych ... Chociaż jest to błędne, w naszym przypadku jest to dopuszczalne. Celem jest zapobieganie temu w przyszłości. Wydaje mi się, że na podstawie komentarzy muszę wykonać tę logikę w procedurach przechowywanych.
Odpowiedzi:
Odpowiedź brzmi tak". Możesz to zrobić za pomocą filtrowanego indeksu (patrz dokumentacja tutaj ).
Na przykład możesz wykonać:
Tworzy to unikalny indeks, tylko w nowych wierszach, a nie w starych wierszach. Ten konkretny preparat pozwoliłby na duplikaty z istniejącymi wartościami.
Jeśli masz tylko garść duplikatów, możesz zrobić coś takiego:
źródło
Tak, możesz to zrobić.
Oto tabela z duplikatami:
Zignorujmy istniejące i upewnij się, że nie można dodawać nowych duplikatów:
Przetestujmy to rozwiązanie:
źródło
UNIQUE
ograniczenie w kolumnie dopuszczającej wartości zerowe zapewnia, że istnieje co najwyżej jednaNULL
wartość. Standard SQL (i prawie wszystkie pozostałe SQL DBMS) mówi, że powinien dopuszczać dowolną liczbęNULL
wartości (tzn. Ograniczenie powinno ignorować wartości puste).Filtrowany unikalny indeks jest genialnym pomysłem, ale ma niewielką wadę - bez względu na to, czy używasz
WHERE identity_column > <current value>
warunku, czyWHERE identity_column NOT IN (<list of ids for duplicate values here>)
.Przy pierwszym podejściu nadal będziesz mógł wstawiać zduplikowane dane w przyszłości, duplikaty istniejących (teraz) danych. Na przykład, jeśli masz teraz (nawet tylko jeden) wiersz
CompanyName = 'Software Inc.'
, indeks nie zabrania wstawiania jeszcze jednego wiersza o tej samej nazwie firmy. Zabrania to tylko, jeśli spróbujesz dwa razy.W drugim podejściu jest poprawa, powyższe nie zadziała (co jest dobre.) Jednak nadal będziesz mógł wstawić więcej duplikatów lub istniejących duplikatów. Na przykład, jeśli masz teraz (dwa lub więcej) wierszy
CompanyName = 'DoubleData Co.'
, indeks nie zabrania wstawiania jeszcze jednego wiersza o tej samej nazwie firmy. Zabrania to tylko, jeśli spróbujesz dwa razy.(Aktualizacja) Można to poprawić, jeśli dla każdej zduplikowanej nazwy trzymasz z listy wykluczeń jeden identyfikator. Jeśli, podobnie jak w powyższym przykładzie, są 4 wiersze z duplikatem
CompanyName = DoubleData Co.
i identyfikatorami4,6,8,9
, lista wykluczeń powinna mieć tylko 3 z tych identyfikatorów.Przy drugim podejściu kolejną wadą jest kłopotliwy warunek (ile kłopotliwy zależy od liczby duplikatów w pierwszej kolejności), ponieważ SQL Server nie wydaje się obsługiwać
NOT IN
operatora wWHERE
części przefiltrowanych indeksów. Zobacz SQL-Fiddle . Zamiast tegoWHERE (CompanyID NOT IN (3,7,4,6,8,9))
musisz mieć coś takiegoWHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
, że nie jestem pewien, czy z takim stanem mają wpływ na wydajność, jeśli masz setki zduplikowanych nazw.Innym rozwiązaniem (podobnym do @Aleksa Kuzniecowa) jest dodanie kolejnej kolumny, wypełnienie jej numerami rang i dodanie unikalnego indeksu obejmującego tę kolumnę:
Wstawienie wiersza o zduplikowanej nazwie nie powiedzie się z powodu
DEFAULT 1
właściwości i unikalnego indeksu. To wciąż nie jest w 100% niezawodne (podczas gdy Alex jest). Duplikaty nadal będą się pojawiać, jeśliRn
jest to jawnie ustawione wINSERT
instrukcji lub jeśliRn
wartości są złośliwie aktualizowane.SQL-Fiddle-2
źródło
Inną alternatywą jest napisanie funkcji skalarnej, która sprawdza, czy wartość już istnieje w tabeli, a następnie wywołanie tej funkcji z ograniczenia sprawdzającego.
To zrobi okropne rzeczy do wykonania.
źródło
Szukam tego samego - utwórz niezaufany unikalny indeks, aby istniejące złe dane były ignorowane, ale nowe rekordy nie mogą być duplikatami niczego, co już istnieje.
Czytając ten wątek, przychodzi mi do głowy, że lepszym rozwiązaniem jest napisanie wyzwalacza, który sprawdzi [wstawiony] w tabeli nadrzędnej pod kątem duplikatów, a jeśli między tymi tabelami istnieje jakikolwiek duplikat, ROLLBACK TRAN.
źródło