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 OBCYograniczenie może wskazywać tylko na jeden stół, a każdy stół może mieć tylko jedenKLUCZ PODSTAWOWYograniczenie. -
Lub możesz mieć wiele
KLUCZ OBCYograniczenia 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: