Zasady ograniczeń FK
Aby odpowiedzieć na pytanie w tytule i na końcu tekstu:
„Nadal chciałbym wiedzieć, jak mieć jeden klucz obcy odwołujący się do dwóch kluczy podstawowych”.
To niemożliwe.
-
KLUCZ OBCY
ograniczenie może wskazywać tylko na jeden stół, a każdy stół może mieć tylko jedenKLUCZ PODSTAWOWY
ograniczenie. -
Lub możesz mieć wiele
KLUCZ OBCY
ograniczenia w tej samej kolumnie (kolumnach) odwołujące się do jednejKLUCZ PODSTAWOWY
(innej) tabeli każdy. (Rzadko przydatne.)
Jednak , pojedynczy PK lub FK może obejmuje wiele kolumn.
A FK może odwoływać się do dowolnych jawnie zdefiniowanych unikalnych (zestawów) kolumn w celu, nie tylko do PK. Podręcznik:
Wielokolumnowy dokument PK lub UNIKALNE
do ograniczenia można się odwoływać tylko przez wielokolumnowe ograniczenie FK z pasującymi typami kolumn.
O co prosisz
Ponieważ nie można użyć tej samej kolumny więcej niż raz na liście kolumn UNIKALNE
lub KLUCZ PODSTAWOWY
ograniczenie, lista docelowa KLUcza OBCEGO
nie można również użyć tej samej kolumny więcej niż raz. Ale nic nie stoi na przeszkodzie, abyśmy używali tej samej kolumny więcej niż raz w źródle lista. W tym tkwi potencjał wdrożenia tego, o co prosisz (ale prawdopodobnie nie chciałeś):
"W statystyce_zespołu
tabela team_statistics.team_id
powinien być kluczem obcym, który odwołuje się do matches.team_id
i matches.team_id1
Kombinacja (team_id, team_id1)
w tabeli dopasowania
musiałby być zdefiniowany UNIKALNY
. Wartości w team_statistics.team_id
będzie ograniczony do przypadków z team =team1
w tabeli dopasowania
jako logiczna konsekwencja:
ALTER TABLE matches
ADD constraint matches_teams_groups_uni UNIQUE (team_id, team_id1);
ALTER TABLE team_statistics
ADD constraint team_statistics_team_group fkey
FOREIGN KEY (team_id, team_id) -- same column twice!
REFERENCES matches(team_id, team_id1);
Może nawet mieć sens w przypadku niektórych konfiguracji, ale nie Twojej.
Czego prawdopodobnie potrzebujesz
Domyślam się, że chcesz czegoś takiego:
(match_id, team_id)
w tabeli team_statistics
powinien być kluczem obcym, który odwołuje się do albo (match_id, team_id)
lub (match_id, team_id1)
w tabeli dopasowania
.
A to nie jest możliwe z ograniczeniami FK i tylko dwoma tabelami. możesz nadużycie SPRAWDZENIA
ograniczenie z fałszywym IMMUTABLE
funkcji i ustaw ją NIE WAŻNE
. Zobacz rozdział „Tańsze z ograniczeniem CHECK” w tej odpowiedzi:
Ale to zaawansowana sztuczka i mniej niezawodna. Nie moja sugestia tutaj, więc nie będę się rozwijał. Proponuję normalizować Twój schemat w użyteczny sposób, na przykład:
CREATE TABLE team (team_id serial PRIMARY KEY
, team text NOT NULL UNIQUE); -- add more attributes for team
CREATE TABLE match (match_id serial PRIMARY KEY); -- add more attributes for match
CREATE TABLE match_team (
match_id int REFERENCES match -- short notation for FK
, team_id int REFERENCES team
, home boolean -- TRUE for home team, FALSE for away team
, innings_score int
-- more attributes of your original "team_statistics"
, PRIMARY KEY (match_id, team_id, home) -- !!! (1st column = match_id)
, UNIQUE (team_id, match_id) -- optional, (1st column = team_id)
);
dom
oznacza drużynę gospodarzy meczu, ale poprzez uwzględnienie w PK ogranicza również do maksymalnie dwóch drużyn na mecz . (Kolumny PK są zdefiniowane NOT NULL
pośrednio.)
Opcjonalny UNIKALNY
ograniczenie na (team_id, match_id)
uniemożliwia drużynom grę przeciwko sobie. Używając odwróconej sekwencji kolumn indeksowych (nieistotnych dla egzekwowania reguły) zapewnia to również indeks komplementarny do PK, co zazwyczaj jest również przydatne. Zobacz:
możesz dodaj oddzielne match_team_statistics
, ale byłoby to tylko opcjonalne rozszerzenie 1:1 do match_team
Teraz. Alternatywnie po prostu dodaj kolumny do match_team
.
Mogę dodać widoki dla typowych wyświetlaczy, takich jak:
CREATE VIEW match_result AS
SELECT m.match_id
, concat_ws(' : ', t1.team, t2.team) AS home_vs_away_team
, concat_ws(' : ', mt1.innings_score, mt2.innings_score) AS result
FROM match m
LEFT JOIN match_team mt1 ON mt1.match_id = m.match_id AND mt1.home
LEFT JOIN team t1 ON t1.team_id = mt1.team_id
LEFT JOIN match_team mt2 ON mt2.match_id = m.match_id AND NOT mt2.home
LEFT JOIN team t2 ON t2.team_id = mt2.team_id;
Podstawowe porady: