Czy mogę mieć klucz obcy odwołujący się do kolumny w widoku w programie SQL Server?

84

W SQL Server 2008 i podane

TableA(A_ID, A_Data)
TableB(B_ID, B_Data)
ViewC(A_or_B_ID, A_or_B_Data)

czy można zdefiniować TableZ(A_or_B_ID, Z_Data)takie, że Z.A_or_B_IDkolumna jest ograniczona do wartości znajdujących się w ViewC? Czy można to zrobić za pomocą klucza obcego w widoku?

marc
źródło

Odpowiedzi:

108

Nie możesz odwołać się do widoku w kluczu obcym.

Brian Fisher
źródło
38
czy jest to ograniczenie serwera SQL, czy jest to nierozsądne pragnienie?
Aaron Anodide
1
@Brian Ja też chciałbym wiedzieć, czy jest to ograniczenie SQL Servera, czy nieracjonalna rzecz, ponieważ w tym momencie zamierzam emulować widok za pomocą wyzwalaczy tylko po to, aby uzyskać obsługę FK (chociaż używam MySql ).
Sanki
4
To jest dobra odpowiedź na te dodatkowe pytania - stackoverflow.com/questions/3833150/ ...
Chris Halcrow
Nie jestem pewien, jak to jest dobra odpowiedź na te pytania ... chodzi o inny DBMS i mówię, że widoki zostały zaprojektowane do ukrywania szczegółów schematu i wygody użytkownika. Po pierwsze, ok ... ale to nie byłaby pierwsza rzecz, jaka kiedykolwiek znalazłaby solidne przypadki użycia poza początkowym projektem. Po drugie, nie jestem pewien, dlaczego FK by tego nie zrobił. Widok może być dowolnym zapytaniem, którego nawet nie musi wyciągać z tabeli, może to być zbiór stałych połączonych razem ... klucz obcy wydaje się w tym przypadku cholernie rozsądny. Jeśli jest powód, dla którego nie, mam nadzieję na coś głębszego.
George Mauer
27

W starszych wersjach SQL Server klucze obce były możliwe tylko poprzez wyzwalacze. Możesz naśladować niestandardowy klucz obcy, tworząc wyzwalacz wstawiania, który sprawdza, czy wstawiona wartość pojawia się również w jednej z odpowiednich tabel.

lorin_f
źródło
3
witamy w StackOverflow. Znalazłem wartość w Twojej odpowiedzi, ponieważ zawiera obejście, ale prawidłowa odpowiedź jest zaakceptowana, a pytanie ma więcej niż 4 lata, więc po prostu nie głosuję, ale nie chciałem wyjść bez tego komentarza.
jachguate
16

Jeśli naprawdę potrzebujesz A_or_B_IDw TableZ, masz dwie podobne opcje:

1) Dodaj wartość null A_IDi B_IDkolumny do tabeli z, utwórz A_or_B_IDkolumnę obliczaną za pomocą ISNULL na tych dwóch kolumnach i dodaj ograniczenie CHECK takie, że tylko jeden z nich A_IDlub B_IDnie jest pusty

2) Dodaj kolumnę TableName do tabeli z, ograniczoną tak, aby zawierała A lub B. Teraz utwórz A_IDi B_IDjako kolumny obliczeniowe, które mają wartość różną od null tylko wtedy, gdy zostanie nazwana odpowiednia tabela (używając wyrażenia CASE). Niech też się utrzymują

W obu przypadkach masz teraz kolumny A_IDi, B_IDktóre mogą mieć odpowiednie klucze obce do tabel podstawowych. Różnica polega na tym, które kolumny są obliczane. Nie potrzebujesz również TableName w opcji 2 powyżej, jeśli domeny dwóch kolumn ID nie nakładają się - o ile wyrażenie przypadku może określić, do której domeny A_or_B_ID należy

(Dzięki komentarzowi za naprawienie mojego formatowania)

Damien_The_Unbeliever
źródło
Umieść słowa z podkreśleniem w back-tickach: A_or_B_ID
Bill Karwin
Pracuję nad dodaniem kilku funkcji do starszego systemu i jest to świetny sposób na połączenie starego i nowego. Dziękuję Ci!
David Gunderson
8

Przepraszamy, nie można FK do widoku w programie SQL Server.

Jarrett Meyer
źródło
4

Jest inna opcja. Traktuj TableA i TableB jako podklasy nowej tabeli o nazwie TablePrime. Dostosuj wartości identyfikatora TableB, aby nie pokrywały się z wartościami identyfikatora TableA. Utwórz identyfikator w TablePrime jako PK i wstaw wszystkie identyfikatory TableA i TableB (dostosowane) do TablePrime. Spraw, aby TableA i TableB miały relacje FK na ich PK z tym samym identyfikatorem w TablePrime.

Masz teraz wzorzec nadtypu / podtypu i możesz tworzyć ograniczenia do TablePrime (gdy chcesz albo A-albo-B ) lub jednej z pojedynczych tabel (gdy chcesz tylko A lub tylko B ).

Jeśli potrzebujesz więcej informacji, zapytaj. Istnieją odmiany, które pozwolą Ci upewnić się, że A i B wzajemnie się wykluczają, a może to, z czym pracujesz, może być jednym i drugim w tym samym czasie. Najlepiej sformalizować to w FK, jeśli to możliwe.

ErikE
źródło
2

Łatwiej jest dodać ograniczenie, które odwołuje się do funkcji zdefiniowanej przez użytkownika, która wykonuje sprawdzenie za Ciebie, fCheckIfValueExists (columnValue), które zwraca true, jeśli wartość istnieje, i false, jeśli nie.

Zaletą jest to, że może odbierać wiele kolumn, wykonywać z nimi obliczenia, akceptować wartości null i akceptować wartości, które nie odpowiadają dokładnie kluczowi głównemu lub porównują się z wynikami łączenia.

Wadą jest to, że optymalizator nie może wykorzystać wszystkich swoich sztuczek z kluczami obcymi.

Camilo J.
źródło
1
Wadą jest to, że optymalizator nie może używać wszystkich swoich sztuczek z kluczami obcymi ... ... i że funkcja będzie uruchamiana dla każdego wstawionego / zaktualizowanego wiersza (więc niezbyt przyjemne dla zestawów).
jimbobmcgee
1

Przepraszamy, w ścisłym znaczeniu tego słowa, nie, nie możesz ustawić kluczy obcych w widokach. Oto dlaczego:

InnoDB to jedyny wbudowany mechanizm przechowywania danych dla MySQL, który obsługuje klucze obce. Każda tabela InnoDB zostanie zarejestrowana w information_schema.tables z silnikiem = 'InnoDB'.

Widoki, mimo że są zarejestrowane w information_schema.tables, mają NULL silnik magazynu. W MySQL nie ma mechanizmów, które pozwalałyby na umieszczanie kluczy obcych w dowolnej tabeli z niezdefiniowanym silnikiem przechowywania.

Dzięki!

Abdul Aziz Al Basyir
źródło
to pytanie dotyczy serwera sql
George Mauer