sql >> Databáze >  >> RDS >> PostgreSQL

Jak mít cizí klíč směřující na dva primární klíče?

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 jednu PRIMÁRNÍ KLÍČ omezení.

  • Nebo můžete mít více CIZI KLÍČ omezení na stejný sloupec(y) odkazující na jeden PRIMÁ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:



  1. Top 5 bezplatných nástrojů pro návrh databáze

  2. jak přidat hodiny a minuty do curdate mysql

  3. Jak použít procento (%) v LIKE, aniž by to bylo považováno za zástupný znak?

  4. Oracle 12c XML získá hodnotu z odpovědi