PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Bagaimana cara memiliki kunci asing yang menunjuk ke dua kunci utama?

Aturan untuk batasan FK

Untuk menjawab pertanyaan di judul dan di akhir teks Anda:

"Saya masih ingin tahu cara memiliki satu kunci asing yang mereferensikan dua kunci utama."

Itu tidak mungkin.

  • FOREIGN KEY batasan hanya dapat menunjuk ke satu tabel dan setiap tabel hanya boleh memiliki satu PRIMARY KEY kendala.

  • Atau Anda dapat memiliki beberapa FOREIGN KEY batasan pada kolom yang sama yang mereferensikan satu PRIMARY KEY dari tabel (berbeda) masing-masing. (Jarang berguna.)

Namun , satu PK atau FK bisa span beberapa kolom.
Dan FK dapat mereferensikan setiap kolom (kumpulan) unik yang didefinisikan secara eksplisit dalam target, bukan hanya PK. Manual:

PK multikolom atau UNIQUE batasan hanya dapat direferensikan oleh batasan FK multikolom dengan jenis kolom yang cocok.

Apa yang Anda tanyakan

Karena tidak diperbolehkan menggunakan kolom yang sama lebih dari satu kali dalam daftar kolom UNIQUE atau PRIMARY KEY kendala, daftar target FOREIGN KEY juga tidak dapat menggunakan kolom yang sama lebih dari satu kali. Namun tidak ada yang menghalangi kami untuk menggunakan kolom yang sama lebih dari satu kali di sumber daftar. Di sinilah letak potensi untuk menerapkan apa yang Anda minta (tetapi mungkin tidak bermaksud demikian):

"Dalam team_statistics tabel team_statistics.team_id harus berupa kunci asing yang mereferensikan matches.team_id dan matches.team_id1 "

Kombinasi (team_id, team_id1) dalam tabel matches perlu didefinisikan UNIQUE . Nilai dalam team_statistics.team_id akan dibatasi untuk kasus dengan team = team1 dalam tabel matches sebagai konsekuensi logis:

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

Bahkan mungkin masuk akal untuk penyiapan tertentu, tetapi tidak untuk Anda.

Yang mungkin Anda butuhkan

Dugaan saya yang terpelajar adalah Anda menginginkan sesuatu seperti ini:

(match_id, team_id) dalam tabel team_statistics harus berupa kunci asing yang mereferensikan salah satu (match_id, team_id) atau (match_id, team_id1) dalam tabel matches .

Dan itu tidak mungkin dengan batasan FK dan hanya dua tabel. Anda bisa menyalahgunakan CHECK kendala dengan IMMUTABLE fake palsu fungsi dan jadikan NOT VALID . Lihat bab "Lebih murah dengan batasan PERIKSA" dalam jawaban ini:

Tapi itu tipuan tingkat lanjut dan kurang bisa diandalkan. Bukan saran saya di sini, jadi saya tidak akan menguraikannya. Saya menyarankan untuk menormalkan skema Anda dengan cara yang bermanfaat, seperti:

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 menandai tim tuan rumah pertandingan tetapi, dengan dimasukkan dalam PK, juga membatasi hingga maksimal dua tim per pertandingan . (Kolom PK didefinisikan NOT NULL secara implisit.)

Opsi UNIQUE batasan pada (team_id, match_id) mencegah tim bermain melawan diri mereka sendiri. Dengan menggunakan urutan kolom indeks terbalik (tidak relevan untuk menegakkan aturan) ini juga menyediakan indeks yang melengkapi PK, yang biasanya juga berguna. Lihat:

Anda bisa tambahkan match_team_statistics yang terpisah , tapi itu hanya akan menjadi ekstensi 1:1 opsional untuk match_team sekarang. Atau cukup tambahkan kolom ke match_team .

Saya mungkin menambahkan tampilan untuk tampilan biasa, seperti:

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;

Saran dasar:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. pg_dump dengan pengguna jangan superadmin dan objek besar

  2. Pernyataan KASUS Postgres dalam sisipan

  3. Lokasi database postgresql di OS X?

  4. Status SQL Postgres:22P02

  5. Sisipkan lambat di PostgreSQL menggunakan JDBC