Pravidla pro omezení FK
Chcete-li odpovědět na otázku v nadpisu a na konci vašeho textu:
"Stále bych rád věděl, jak mít jeden cizí klíč odkazující na dva primární klíče."
To je nemožné.
-
CIZI KLÍČ
omezení může ukazovat pouze na jedno tabulka a každá tabulka může mít pouze jednuPRIMÁRNÍ KLÍČ
omezení. -
Nebo můžete mít více
CIZI KLÍČ
omezení na stejný sloupec(y) odkazující na jedenPRIMÁRNÍ KLÍČ
každý z (jiné) tabulky. (Zřídka užitečné.)
Nicméně , jeden PK nebo FK může span více sloupců.
A FK může odkazovat na jakýkoli explicitně definovaný jedinečný (množinu) sloupců v cíli, nejen na PK. Příručka:
Vícesloupcový PK nebo UNIKÁT
omezení lze odkazovat pouze pomocí vícesloupcového omezení FK s odpovídajícími typy sloupců.
Na co se ptáte
Protože není povoleno použít stejný sloupec více než jednou v seznamu sloupců UNIQUE
nebo PRIMÁRNÍ KLÍČ
omezení, cílový seznam CIZIHO KLÍČE
také nelze použít stejný sloupec více než jednou. Nic nám ale nebrání použít stejný sloupec ve zdroji vícekrát seznam. Zde se skrývá potenciál k realizaci toho, co požadujete (ale pravděpodobně jste to nechtěli):
"V týmových_statistikách
tabulku team_statistics.team_id
by měl být cizí klíč, který odkazuje na matches.team_id
a matches.team_id1
"
Kombinace (id_týmu, id_týmu1)
v tabulce odpovídá
by musel být definován UNIQUE
. Hodnoty v team_statistics.team_id
by bylo omezeno na případy s tým =tým1
v tabulce odpovídá
jako logický důsledek:
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);
Pro určitá nastavení to může mít smysl, ale ne pro vaše.
Co pravděpodobně potřebujete
Můj kvalifikovaný odhad je, že chcete něco takového:
(id_shody, ID_týmu)
v tabulce týmové_statistiky
by měl být cizí klíč, který odkazuje na buď (id_shody, ID_týmu)
nebo (id_shody, id_týmu1)
v tabulce odpovídá
.
A to není možné s omezeními FK a pouze dvěma tabulkami. Mohli byste zneužít CHECK
omezení s falešným IMMUTABLE
funkci a udělejte ji NEPLATNÉ
. Viz kapitola "Levnější s omezením CHECK" v této odpovědi:
Ale to je pokročilý trik a méně spolehlivý. Nejedná se zde o můj návrh, takže se nebudu rozepisovat. Navrhuji normalizovat vaše schéma užitečným způsobem, například:
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)
);
domov
označuje domácí tým zápasu, ale zahrnutím do PK také omezuje maximálně dva týmy na zápas . (Sloupce PK jsou definovány NOT NULL
implicitně.)
Volitelný UNIQUE
omezení na (team_id, match_id)
brání týmům hrát proti sobě. Použitím obrácené sekvence sloupců indexu (nepodstatné pro vynucení pravidla) to také poskytuje index doplňující PK, což je obvykle také užitečné. Viz:
Mohli byste přidejte samostatnou match_team_statistics
, ale to by bylo pouze volitelné rozšíření 1:1 pro match_team
Nyní. Případně stačí přidat sloupce do match_team
.
Mohl bych přidat zobrazení pro typické displeje, jako:
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;
Základní rada: