PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak mieć klucz obcy wskazujący na dwa klucze podstawowe?

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 OBCY ograniczenie może wskazywać tylko na jeden stół, a każdy stół może mieć tylko jeden KLUCZ PODSTAWOWY ograniczenie.

  • Lub możesz mieć wiele KLUCZ OBCY ograniczenia w tej samej kolumnie (kolumnach) odwołujące się do jednej KLUCZ 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:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Knex.js - Jak stworzyć unikalny indeks z klauzulą ​​'gdzie'?

  2. Opcje rozwijane formularzy Pythona wypełniane przez sql

  3. Wymyśl błąd klucza podstawowego w postgresql, heroku, Railsach 4

  4. Jak działa Abs() w PostgreSQL

  5. Funkcja Postgres tworzy, ale nie wykonuje