Na przykład z tabelą podobną do tej:
create table foo(bar int identity, chk char(1) check (chk in('Y', 'N')));
Nie ma znaczenia, czy flaga jest zaimplementowana jako a char(1)
, bit
czy cokolwiek innego. Chcę tylko móc wymusić ograniczenie, które można ustawić tylko w jednym wierszu.
constraint
database-agnostic
referential-integrity
Jack Douglas
źródło
źródło
Odpowiedzi:
SQL Server 2008 - Filtrowany unikalny indeks
źródło
SQL Server 2000, 2005:
Możesz skorzystać z faktu, że tylko jeden null jest dozwolony w unikalnym indeksie:
w 2000 roku możesz potrzebować
SET ARITHABORT ON
(dzięki @gbn za te informacje)źródło
Wyrocznia:
Ponieważ Oracle nie indeksuje wpisów, w których wszystkie indeksowane kolumny są puste, możesz użyć unikalnego indeksu opartego na funkcjach:
Indeks ten indeksuje tylko najwyżej jeden wiersz.
Znając ten fakt indeksu, możesz również nieco zaimplementować kolumnę bitową:
Tutaj możliwe wartości dla kolumny
chk
toY
iNULL
. Tylko jeden wiersz może mieć tę wartośćY.
źródło
not null
ograniczenia?not null
ograniczenie, jeśli nie chcesz wartości zerowych (nie było dla mnie jasne ze specyfikacji pytań). W każdym przypadku tylko jeden wiersz może mieć wartość „Y”.default
)?Y
albonull
zobacz moją aktualizację.null
pomijane są - być może kosztem pewnej przejrzystościMyślę, że jest to przypadek prawidłowej strukturyzacji tabel w bazie danych. Aby bardziej konkretnie, jeśli masz osobę z wieloma adresami i chcesz, aby jeden był domyślny, myślę, że powinieneś przechowywać identyfikator adresu domyślnego adresu w tabeli osób, a nie mieć domyślnej kolumny w tabeli adresów:
Możesz ustawić DefaultAddressID na wartość zerową, ale w ten sposób struktura wymusza ograniczenie.
źródło
MySQL:
Sprawdź ograniczenia są ignorowane w MySQL więc mamy do rozważenia
null
lubfalse
jako fałszywe itrue
jak prawdziwe. Może mieć maksymalnie 1 wierszchk=true
Można to poprawa dodać wyzwalacz do zmiany rozważyć
false
wtrue
sprawie Insert / aktualizacji jako obejście braku przymusu wyboru - IMO nie jest to poprawa choć.Miałem nadzieję, że będę w stanie użyć char (0), ponieważ to
Niestety, przynajmniej z MyISAM i InnoDB
--edytować
nie jest to jednak dobre rozwiązanie, ponieważ na MySQL
boolean
jest synonimemtinyint(1)
, a zatem dopuszcza wartości inne niż zero od 0 lub 1. Możliwe, żebit
byłby to lepszy wybórźródło
null
,false
,true
- Zastanawiam czy jest coś neater ...SQL Server:
Jak to zrobić:
Najlepszym sposobem jest filtrowany indeks. Wykorzystuje DRI
SQL Server 2008+
Kolumna obliczeniowa o wyjątkowości. Wykorzystuje DRI
Patrz odpowiedź Jacka Douglasa. SQL Server 2005 i wcześniejsze wersje
Indeksowany / zmaterializowany widok, który jest jak filtrowany indeks. Wykorzystuje DRI
Wszystkie wersje.
Wyzwalacz. Używa kodu, a nie DRI.
Wszystkie wersje
Jak tego nie robić:
Zobacz Raz Dwa Trzy Cztery
źródło
PostgreSQL:
--edytować
lub (znacznie lepiej) użyj unikalnego indeksu częściowego :
źródło
Ten rodzaj problemu jest kolejnym powodem, dla którego zadałem to pytanie:
Ustawienia aplikacji w bazie danych
Jeśli w bazie danych znajduje się tabela ustawień aplikacji, może istnieć wpis odwołujący się do identyfikatora jednego rekordu, który ma być uważany za „specjalny”. Następnie po prostu sprawdź, jaki jest identyfikator z tabeli ustawień, w ten sposób nie potrzebujesz całej kolumny, aby ustawić tylko jeden element.
źródło
Możliwe podejścia z wykorzystaniem szeroko wdrażanych technologii:
1) Odwołaj uprawnienia „pisarza” na stole. Utwórz procedury CRUD, które zapewniają wymuszanie ograniczenia na granicach transakcji.
2) 6NF: upuść
CHAR(1)
kolumnę. Dodaj tabelę odwołań ograniczoną, aby jej liczność nie mogła przekraczać jednego:Zmień semantykę aplikacji, aby rozważanym „domyślnym” był wiersz w nowej tabeli. Ewentualnie użyj widoków, aby zamknąć tę logikę.
3) Upuść
CHAR(1)
kolumnę. Dodajseq
kolumnę całkowitą. Umieść wyjątkowe ograniczenieseq
. Zmień semantykę aplikacji, tak aby uważany za „domyślny” był wiersz, w którymseq
wartością jest jedna lubseq
wartość największa / najmniejsza lub podobna. Ewentualnie użyj widoków, aby zamknąć tę logikę.źródło
Dla tych, którzy używają MySQL, oto odpowiednia procedura przechowywana:
Aby upewnić się, że tabela jest czysta i procedura przechowywana działa, zakładając, że domyślnym identyfikatorem jest 200, uruchom następujące kroki:
Oto wyzwalacz, który również pomaga:
Aby upewnić się, że tabela jest czysta i wyzwalacz działa, zakładając, że domyślnym identyfikatorem jest 200, uruchom następujące kroki:
Spróbuj !!!
źródło
W SQL Server 2000 i nowszych można używać widoków indeksowanych do implementowania złożonych (lub wielostołowych) ograniczeń, takich jak to, o które prosisz.
Oracle ma również podobną implementację dla widoków zmaterializowanych z ograniczeniami odroczonego sprawdzania.
Zobacz mój post tutaj .
źródło
Standardowy przejściowy SQL-92, szeroko implementowany np. SQL Server 2000 i nowsze wersje:
Odwołaj uprawnienia „pisarza” ze stołu. Tworzenie dwóch widoków
WHERE chk = 'Y'
iWHERE chk = 'N'
odpowiednio, w tymWITH CHECK OPTION
. DoWHERE chk = 'Y'
widoku dołącz warunek wyszukiwania, aby jego liczność nie mogła przekroczyć jednego. Przyznaj uprawnienia „pisarza” do widoków.Przykładowy kod widoków:
źródło
Oto rozwiązanie dla MySQL i MariaDB z wykorzystaniem wirtualnych kolumn, które są nieco bardziej eleganckie. Wymaga MySQL> = 5.7.6 lub MariaDB> = 5.2:
Utwórz wirtualną kolumnę o wartości NULL, jeśli nie chcesz wymuszać ograniczenia Unique:
(W przypadku MySQL należy użyć
STORED
zamiastPERSISTENT
.)źródło
Standardowy PEŁNY SQL-92: użyj podkwerendy w
CHECK
ograniczeniu, nie jest powszechnie implementowane, np. Obsługiwane w Access2000 (ACE2007, Jet 4.0, cokolwiek) i wyżej, gdy jest w trybie zapytania ANSI-92 .Przykładowy kod:
CHECK
ograniczenia notatek w programie Access są zawsze na poziomie tabeli. PonieważCREATE TABLE
stwierdzenie w pytaniu wykorzystujeCHECK
ograniczenie na poziomie wiersza , należy je nieznacznie zmienić, dodając przecinek:źródło
Przeglądałem tylko odpowiedzi, więc mogłem nie zauważyć podobnej odpowiedzi. Chodzi o to, aby użyć wygenerowanej kolumny, która jest albo pk, albo stałą, która nie istnieje jako wartość dla pk
AFAIK jest to poprawne w SQL2003 (ponieważ szukasz rozwiązania agnostycznego). DB2 na to pozwala, nie wiadomo, ilu innych dostawców to akceptuje.
źródło