PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Làm thế nào để có một khóa ngoại trỏ đến hai khóa chính?

Quy tắc cho các ràng buộc FK

Để trả lời câu hỏi trong tiêu đề và ở cuối văn bản của bạn:

"Tôi vẫn muốn biết cách có một khóa ngoại tham chiếu đến hai khóa chính."

Điều đó là không thể.

  • NGOẠI KHÓA ràng buộc chỉ có thể trỏ đến một bảng và mỗi bảng chỉ có thể có một KEY CHÍNH ràng buộc.

  • Hoặc bạn có thể có nhiều NGOẠI KHÓA các ràng buộc trên cùng (các) cột tham chiếu đến một CHÌA KHÓA CHÍNH của mỗi bảng (khác nhau). (Hiếm khi hữu ích.)

Tuy nhiên , một PK hoặc FK có thể mở rộng nhiều cột.
Và FK có thể tham chiếu bất kỳ (các) cột (tập hợp) cột duy nhất được xác định rõ ràng nào trong mục tiêu, không chỉ PK. Hướng dẫn sử dụng:

PK nhiều cột hoặc DUY NHẤT ràng buộc chỉ có thể được tham chiếu bởi ràng buộc FK nhiều cột với các loại cột phù hợp.

Những gì bạn hỏi

Vì không được phép sử dụng cùng một cột nhiều lần trong danh sách cột của một UNIQUE hoặc PRIMARY KEY ràng buộc, danh sách đích của một FOREIGN KEY cũng không thể sử dụng cùng một cột nhiều hơn một lần. Nhưng không có gì ngăn chúng tôi sử dụng cùng một cột nhiều lần trong nguồn danh sách. Đây là tiềm năng để triển khai những gì bạn đang yêu cầu (nhưng có thể không cố ý):

"Trong team_stosystem lập bảng team_stosystem.team_id phải là khóa ngoại tham chiếu đến match.team_id trận đấu.team_id1 "

Sự kết hợp của (team_id, team_id1) trong bảng phù hợp sẽ cần được xác định UNIQUE . Các giá trị trong team_stosystem.team_id sẽ bị hạn chế trong các trường hợp có team =team1 trong bảng phù hợp như một hệ quả logic:

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

Thậm chí có thể có ý nghĩa đối với một số thiết lập nhất định, nhưng không phải của bạn.

Những gì bạn có thể cần

Tôi đoán là bạn muốn một cái gì đó như thế này:

(match_id, team_id) trong bảng team_stosystem phải là khóa ngoại tham chiếu đến một trong hai (match_id, team_id) hoặc (match_id, team_id1) trong bảng phù hợp .

Và điều đó là không thể với các ràng buộc FK và chỉ hai bảng. Bạn có thể lạm dụng KIỂM TRA ràng buộc với IMMUTABLE giả hoạt động và làm cho nó KHÔNG HỢP LỆ . Xem chương "Rẻ hơn với ràng buộc KIỂM TRA" trong câu trả lời này:

Nhưng đó là thủ thuật tiên tiến và ít đáng tin cậy hơn. Không phải đề xuất của tôi ở đây, vì vậy tôi sẽ không nói chi tiết. Tôi khuyên bạn nên chuẩn hóa lược đồ của bạn theo cách hữu ích, như:

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 đánh dấu đội chủ nhà của trận đấu nhưng bằng cách đưa vào PK, cũng hạn chế ở mức tối đa hai đội mỗi trận . (Các cột PK được xác định NOT NULL ngầm định.)

UNIQUE tùy chọn ràng buộc về (team_id, match_id) ngăn các đội chơi với chính họ. Bằng cách sử dụng trình tự đảo ngược của các cột chỉ mục (không liên quan đến việc thực thi quy tắc), điều này cũng cung cấp một chỉ mục bổ sung cho PK, thường cũng hữu ích. Xem:

Bạn có thể thêm một match_team_stosystem riêng biệt , nhưng đó sẽ chỉ là phần mở rộng 1:1 tùy chọn cho match_team bây giờ. Ngoài ra, chỉ cần thêm các cột vào match_team .

Tôi có thể thêm lượt xem cho các màn hình điển hình, như:

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;

Lời khuyên cơ bản:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Buộc Liquibase ánh xạ Blob tới BYTEA trên PostgreSQL

  2. Django haystack với Elasticsearch không thể tìm thấy cơ sở dữ liệu khi xây dựng lại chỉ mục

  3. Lỗi trong diễn biến trên Heroku

  4. Có cách nào để lập chỉ mục một cách hữu ích cột văn bản có chứa các mẫu regex không?

  5. lỗi:Xác thực danh tính không thành công cho người dùng