sql >> Database >  >> RDS >> PostgreSQL

Hoe krijg ik een externe sleutel die naar twee primaire sleutels wijst?

Regels voor FK-beperkingen

Om de vraag in de titel en aan het einde van uw tekst te beantwoorden:

"Ik zou nog steeds graag willen weten hoe ik één externe sleutel kan hebben die verwijst naar twee primaire sleutels."

Dat is onmogelijk.

  • Een FOREIGN KEY beperking kan slechts naar één . verwijzen tafel en elke tafel kan slechts één . hebben PRIMARY KEY beperking.

  • Of u kunt meerdere . hebben FOREIGN KEY beperkingen op dezelfde kolom(men) die verwijzen naar één PRIMARY KEY van elk een (andere) tafel. (Zelden nuttig.)

Echter , een enkele PK of FK kan beslaan meerdere kolommen.
En een FK kan verwijzen naar elke expliciet gedefinieerde unieke (set van) kolom(men) in het doel, niet alleen de PK. De handleiding:

Een PK met meerdere kolommen of UNIQUE Er kan alleen naar een beperking worden verwezen door een FK-beperking met meerdere kolommen met overeenkomende kolomtypen.

Wat je vraagt

Aangezien het niet is toegestaan ​​om dezelfde kolom meer dan één keer te gebruiken in de kolomlijst van een UNIQUE of PRIMARY KEY beperking, de doellijst van een FOREIGN KEY kan dezelfde kolom ook niet meer dan één keer gebruiken. Maar er is niets dat ons ervan weerhoudt dezelfde kolom meer dan één keer te gebruiken in de bron lijst. Hierin ligt het potentieel om te implementeren wat je vraagt ​​(maar waarschijnlijk niet de bedoeling was):

"In de team_statistics tabel de team_statistics.team_id moet een externe sleutel zijn die verwijst naar matches.team_id en matches.team_id1 "

De combinatie van (team_id, team_id1) in tabel matches zou moeten worden gedefinieerd UNIQUE . Waarden in team_statistics.team_id zou beperkt zijn tot gevallen met team = team1 in tabel matches als logisch gevolg:

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);

Misschien zelfs zinvol voor bepaalde instellingen, maar niet voor de jouwe.

Wat je waarschijnlijk nodig hebt

Mijn weloverwogen gok is dat je zoiets als dit wilt:

(match_id, team_id) in tabel team_statistics moet een externe sleutel zijn die verwijst naar ofwel (match_id, team_id) of (match_id, team_id1) in tabel matches .

En dat is niet mogelijk met FK-beperkingen en slechts twee tabellen. Je zou misbruik maken van een CHECK beperking met een nep IMMUTABLE functie en maak deze NOT VALID . Zie hoofdstuk "Goedkoper met een CHECK-beperking" in dit antwoord:

Maar dat is geavanceerde bedrog en minder betrouwbaar. Niet mijn suggestie hier, dus ik ga niet uitweiden. Ik stel voor om normaliseren uw schema op een nuttige manier, zoals:

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)
);

home markeert het thuisteam van de wedstrijd, maar beperkt door opname in de PK ook tot max. twee teams per wedstrijd . (PK-kolommen zijn gedefinieerd NOT NULL impliciet.)

De optionele UNIQUE beperking op (team_id, match_id) voorkomt dat teams tegen zichzelf spelen. Door de omgekeerde volgorde van indexkolommen te gebruiken (niet relevant voor het afdwingen van de regel) levert dit ook een index op die complementair is aan de PK, wat meestal ook nuttig is. Zie:

Je zou voeg een aparte match_team_statistics toe , maar dat zou slechts een optionele 1:1-extensie zijn voor match_team nu. U kunt ook gewoon kolommen toevoegen aan match_team .

Ik zou weergaven kunnen toevoegen voor typische displays, zoals:

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;

Basisadvies:



  1. Een zeer beschikbare canvas LMS implementeren met een PostgreSQL-databasecluster

  2. Het schema voor een tabel ophalen

  3. Oracle SQL-query om alle datums van de vorige maand weer te geven

  4. SQL-case wanneer FROM(UNIX_TIME)