sql >> Database teknologi >  >> RDS >> PostgreSQL

Hvordan får man en fremmednøgle til at pege på to primære nøgler?

Regler for FK-begrænsninger

For at besvare spørgsmålet i titlen og i slutningen af ​​din tekst:

"Jeg vil stadig gerne vide, hvordan man har én fremmednøgle, der refererer til to primære nøgler."

Det er umuligt.

  • En UDLANDS NØGLE begrænsning kan kun pege på én tabel, og hver tabel kan kun have én PRIMÆR NØGLE begrænsning.

  • Eller du kan have flere UDLANDS NØGLE begrænsninger på samme kolonne(r), der refererer til én PRIMÆR NØGLE af en (forskellig) tabel hver. (Sjældent nyttigt.)

Men , en enkelt PK eller FK kan spænder over flere kolonner.
Og en FK kan referere til enhver eksplicit defineret unik (sæt af) kolonne(r) i målet, ikke kun PK. Manualen:

En multikolonne PK eller UNIK begrænsning kan kun refereres af en FK-begrænsning med flere kolonner med matchende kolonnetyper.

Hvad du spørger om

Da det ikke er tilladt at bruge den samme kolonne mere end én gang i kolonnelisten for en UNIQUE eller PRIMÆR NØGLE constraint, mållisten for en FOREIGN KEY kan heller ikke bruge samme kolonne mere end én gang. Men der er ikke noget, der forhindrer os i at bruge den samme kolonne mere end én gang i kilden liste. Heri ligger potentialet til at implementere det, du spørger om (men sandsynligvis ikke har tænkt dig):

"I team_statistics tabel team_statistics.team_id skal være en fremmednøgle, der refererer til matches.team_id og matches.team_id1 "

Kombinationen af ​​(team_id, team_id1) i tabel matches skal defineres UNIQUE . Værdier i team_statistics.team_id ville være begrænset til sager med team =team1 i tabel matches som logisk konsekvens:

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

Måske giver det endda mening for visse opsætninger, men ikke dine.

Hvad du sandsynligvis har brug for

Mit veluddannede gæt er, at du vil have sådan noget her:

(match_id, team_id) i tabel team_statistics skal være en fremmednøgle, der henviser til enten (match_id, team_id) eller (match_id, team_id1) i tabel matches .

Og det er ikke muligt med FK-begrænsninger og kun to borde. Du kunne misbruge en CHECK begrænsning med en falsk IMMUTABLE funktion og gør den IKKE GYLDIG . Se kapitlet "Billigere med en CHECK-begrænsning" i dette svar:

Men det er avanceret trick og mindre pålideligt. Ikke mit forslag her, så jeg vil ikke uddybe det. Jeg foreslår at normalisere dit skema på en nyttig måde, såsom:

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

hjem markerer kampens hjemmehold, men ved medtagelse i PK begrænser det også til maks. to hold pr. kamp . (PK-kolonner er defineret IKKE NULL implicit.)

Den valgfrie UNIQUE begrænsning på (team_id, match_id) forhindrer holdene i at spille mod sig selv. Ved at bruge den omvendte sekvens af indekskolonner (irrelevant for at håndhæve reglen) giver dette også et indeks, der er komplementært til PK, hvilket typisk også er nyttigt. Se:

Du kunne tilføje en separat match_team_statistics , men det ville bare være en valgfri 1:1-udvidelse til match_team nu. Alternativt kan du blot tilføje kolonner til match_team .

Jeg kan tilføje visninger til typiske skærme, såsom:

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;

Grundlæggende råd:



  1. Sender liste over parametre til SQL i psycopg2

  2. mysqli_real_escape_string fungerer ikke korrekt

  3. ASCII() eksempler – MySQL

  4. SQL IN-sætning - behold dubletter, når du returnerer resultater