PostgreSQL

Ràng buộc FOREIGN KEY – Thiết lập khóa ngoại cho bảng

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng
Được viết bởi Minh Hoàng

Series chia sẻ về PostgreSQL – Cơ sở dữ liệu mã nguồn mở tiên tiến nhất thế giới.

Bằng cách thêm ràng buộc khóa ngoại FOREIGN KEY vào một cột khi tạo bảng, giá trị có thể được lưu trữ trong cột đích có thể được giới hạn ở dữ liệu được lưu trữ trong bảng khác.

Bài viết này sẽ giải thích cách sử dụng ràng buộc khóa ngoại FOREIGN KEY trong PostgreSQL.

Khóa ngoại (foreign key) là một cột hoặc một nhóm cột trong bảng tham chiếu đến khóa chính của bảng khác.

Bảng có chứa khóa ngoại được gọi là bảng tham chiếu hoặc bảng con. Và bảng được tham chiếu bởi khóa ngoại được gọi là bảng được tham chiếu hoặc bảng cha.

Một bảng có thể có nhiều khóa ngoại tùy thuộc vào mối quan hệ của nó với các bảng khác.

Trong PostgreSQL, bạn xác định khóa ngoại bằng cách sử dụng ràng buộc khóa ngoại FOREIGN KEY. Ràng buộc khóa ngoại giúp duy trì tính toàn vẹn tham chiếu của dữ liệu giữa bảng con và bảng cha.

Ràng buộc khóa ngoại chỉ ra rằng các giá trị trong một cột hoặc một nhóm cột trong bảng con bằng với các giá trị trong một cột hoặc một nhóm cột của bảng cha.

1. Cách sử dụng ràng buộc FOREIGN KEY

1. Cách sử dụng ràng buộc FOREIGN KEY

Bằng cách đặt ràng buộc khóa ngoại FOREIGN KEY trên một cột, bạn có thể giới hạn giá trị được lưu trên cột đó bằng giá trị được lưu ở cột chỉ định trên một bảng khác.

Định dạng như sau:

CREATE TABLE [ IF NOT EXISTS ] table_name (
  column_name data_type REFERENCES reftable [ ( refcolumn ) ]
)

Thiết lập bảng tham chiếu (referenced table) reftable có cột tham chiếu (referenced column) refcolumn cho cột column_name muốn chỉ định ràng buộc khóa ngoại FOREIGN KEY.

Ngoài ra, ràng buộc FOREIGN KEY cũng có thể được đặt trên bảng để thiết lập ràng buộc cho một hoặc nhiều cột thay vì trên cơ sở từng cột:

CREATE TABLE [ IF NOT EXISTS ] table_name (
  column_name1 data_type1, 
  column_name2 data_type2,
  [CONSTRAINT constraint_name] FOREIGN KEY ( column_name1 )
    REFERENCES reftable [ ( refcolumn ) ]
)

Cột được tham chiếu refcolumn bởi ràng buộc khóa ngoại FOREIGN KEY BẮT BUỘC PHẢI CÓ ràng buộc khóa chính PRIMARY KEY hoặc ràng buộc duy nhất UNIQUE.

※Nếu bạn không chỉ định rõ ràng tên cho ràng buộc khóa ngoại [CONSTRAINT constraint_name], PostgreSQL sẽ chỉ định tên mặc định cho ràng buộc khóa ngoại. Theo mặc định, PostgreSQL sử dụng table-name_column-name_fkey làm tên mặc định cho ràng buộc khóa ngoại (Xem hình (*) bên dưới).


Bây giờ sẽ đi vào ví dụ cụ thể. Let’s Go!

Chúng ta sẽ tạo bảng department với vai trò là bảng được tham chiếu dữ liệu về phòng ban. Sau đó, tạo bảng nhân viên staff làm bảng tham chiếu dữ liệu về phòng ban. Sử dụng ràng buộc FOREIGN KEY cho cột liên quan đến phòng ban của bảng staff để chỉ có thể đăng ký dữ liệu được lưu trong bảng department.

Đầu tiên tạo bảng được tham chiếu có tên department trong lược đồ myschema1 của cơ sở dữ liệu mydb:

CREATE TABLE myschema1.department (
  name varchar(10) PRIMARY KEY
);

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (1)

Ràng buộc khóa chính PRIMARY KEY được đặt trên cột được tham chiếu name của bảng được tham chiếu department.

và thêm dữ liệu vào bảng department:

INSERT INTO myschema1.department VALUES
  ('Sales'), 
  ('Accounting'), 
  ('Marketing');

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (2)

Tiếp theo, bảng tham chiếu staff trong lược đồ myschema1 của cơ sở dữ liệu mydb:

CREATE TABLE myschema1.staff(
  id integer, 
  staffname varchar(30), 
  depname varchar(30), 
  FOREIGN KEY (depname) REFERENCES myschema1.department(name)
);

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (3)

Xem thông tin cột và ràng buộc đã tạo của bảng staff (*) :

\d myschema1.staff

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (4)

Bây giờ chúng ta sẽ thêm một số dữ liệu OK vào bảng staff:

INSERT INTO myschema1.staff VALUES
  (1, 'Hoang Ngoc Minh', 'Sales'), 
  (2, 'Minh Hoang Blog', 'Marketing'), 
  (3, 'Hoang Vu Nam Anh', 'Accounting');

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (5)

Vì ràng buộc khóa ngoại được đặt trên cột depname của bảng staff tham chiếu đến cột name của bảng department nên giá trị của cột depname này CHỈ CÓ THỂ thêm một trong các giá trị được lưu trong cột name của bảng department. Cả ba dữ liệu được thêm lần này vào cột depname đều có trong cột name nên đã được thêm thành công.

Tiếp theo, thêm dữ liệu vào bảng staff có chứa giá trị không được lưu trữ trong cột được tham chiếu ở bảng department:

INSERT INTO myschema1.staff VALUES
  (4, 'Vu Huynh Anh Phuong', 'Customer');

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (6)

lần này thì việc thêm dữ liệu đã thất bại vì giá trị depname ‘Customer’ không tìm thấy trong cột name của bảng department.

Bằng cách đặt ràng buộc khóa ngoại FOREIGN KEY theo cách này, bạn có thể giới hạn các giá trị có thể được lưu trữ trong một cột.

2. Xử lý khi dữ liệu của bảng được tham chiếu bị xóa / cập nhật

2. Xử lý khi dữ liệu của bảng được tham chiếu bị xóa / cập nhật

Khi ràng buộc FOREIGN KEY được đặt, chỉ dữ liệu được lưu trữ trong bảng được tham chiếu mới có thể được thêm vào bảng tham chiếu. Ở trạng thái dữ liệu được thêm vào bảng tham chiếu, mà dữ liệu trong bảng được tham chiếu bị xóa hoặc cập nhật thì hai bảng trở nên không nhất quán.

Bạn có thể thiết lập những việc cần làm với dữ liệu trong bảng tham chiếu khi dữ liệu của bảng được tham chiếu cập nhật hoặc xóa.

Sử dụng định dạng sau:

CREATE TABLE [ IF NOT EXISTS ] table_name (
  column_name data_type REFERENCES reftable [ ( refcolumn ) ]
    [ ON DELETE delete_action ]
    [ ON UPDATE update_action ]
)

Hành động [ ON DELETE delete_action ] thiết lập hành vi khi bảng được tham chiếu bị xóa và hành động [ ON UPDATE update_action ] thiết lập hành vi khi bảng được tham chiếu được cập nhật.

Nó có thể được đặt theo cách tương tự ngay cả khi giới hạn khóa ngoại được đặt cho bảng thay vì cho mỗi cột:

CREATE TABLE [ IF NOT EXISTS ] table_name (
  column_name1 data_type1, 
  column_name2 data_type2,
  [CONSTRAINT constraint_name] FOREIGN KEY ( column_name1 )
    REFERENCES reftable [ ( refcolumn ) ]
    [ ON DELETE delete_action ]
    [ ON UPDATE update_action ]
)

Các giá trị có thể được đặt trong action cho mỗi giá trị như sau:

NO ACTION
Hiển thị lỗi (Mặc định)

RESTRICT
Hiển thị lỗi (giống như NO ACTION, sự khác biệt chỉ phát sinh khi bạn xác định ràng buộc khóa ngoại như là DEFERRABLE với chế độ (mode) INITIALLY DEFERRED hoặc INITIALLY IMMEDIATE. Chúng ta sẽ thảo luận thêm về vấn đề này ở bài viết khác)

CASCADE
Trong trường hợp xóa, sẽ tự động xóa tất cả các hàng tham chiếu trong bảng tham chiếu khi các hàng tham chiếu trong bảng được tham chiếu bị xóa.
Trong trường hợp cập nhật, sẽ cập nhật dữ liệu tham chiếu dữ liệu được cập nhật thành một giá trị mới.
Trong thực tế, CASCADE là tùy chọn được sử dụng phổ biến nhất.

SET NULL
Đặt dữ liệu tham chiếu đến dữ liệu đã xóa hoặc cập nhật thành NULL

SET DEFAULT
Đặt dữ liệu tham chiếu đến dữ liệu đã xóa hoặc cập nhật thành giá trị mặc định.


Chúng ta sẽ làm ví dụ với option CASCADE. Nếu dữ liệu bị xóa khỏi bảng được tham chiếu, dữ liệu đang tham chiếu cũng bị xóa. Khi dữ liệu của bảng được tham chiếu được cập nhật, dữ liệu đang tham chiếu cũng được cập nhật về cùng một giá trị.

Bảng được tham chiếu department đã tạo ở trên sẽ tiếp tục được sử dụng.

Bảng tham chiếu staff sẽ được xóa và tạo lại để thêm action với option CASCADE trong lược đồ myschema1 của cơ sở dữ liệu mydb:

DROP TABLE IF EXISTS myschema1.staff;

CREATE TABLE myschema1.staff(
  id integer, 
  staffname varchar(30), 
  depname varchar(30), 
  FOREIGN KEY (depname) REFERENCES myschema1.department(name)
    ON DELETE CASCADE
    ON UPDATE CASCADE
);

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (7)

thêm lại dữ liệu vào bảng staff:

INSERT INTO myschema1.staff VALUES
  (1, 'Hoang Ngoc Minh', 'Sales'), 
  (2, 'Minh Hoang Blog', 'Marketing'), 
  (3, 'Hoang Vu Nam Anh', 'Accounting');

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (8)

Bây giờ chúng ta sẽ xóa một phần dữ liệu khỏi bảng department được tham chiếu:

DELETE FROM myschema1.department
  WHERE name = 'Marketing';

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (9)

Dữ liệu đã bị xóa. Vì CASCADE được chỉ định ON DELETE cho bảng tham chiếu staff, nên tất cả dữ liệu tham chiếu trên bảng staff đến giá trị bị xóa trên bảng được tham chiếu department cũng tự động bị xóa khỏi bảng staff:

SELECT * FROM myschema1.staff;

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (10)

Kết quả dữ liệu đã bị xóa khỏi bảng tham chiếu staff.


Bây giờ, thử cập nhật dữ liệu được tham chiếu trong bảng department với một giá trị mới:

UPDATE myschema1.department SET name = 'Finance'
  WHERE name = 'Accounting';

Dữ liệu đã được cập nhật.

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (11)

CASCADE được chỉ định ON UPDATE cho bảng tham chiếu staff, nên tất cả dữ liệu tham chiếu trên bảng staff đến giá trị được cập nhật trên bảng được tham chiếu department cũng tự động được cập nhật thành cùng một giá trị trên bảng staff:

SELECT * FROM myschema1.staff;

Ràng buộc FOREIGN KEY - Thiết lập khóa ngoại cho bảng (12)

Kết quả dữ liệu của bảng tham chiếu staff cũng đã được cập nhật thành Finance.

3. Thêm ràng buộc FOREIGN KEY vào bảng đã tồn tại

3. Thêm ràng buộc FOREIGN KEY vào bảng đã tồn tại

Để thêm ràng buộc khóa ngoại FOREIGN KEY vào bảng hiện có, bạn sử dụng mẫu sau của câu lệnh ALTER TABLE:

ALTER TABLE bảng_tham_chiếu 
ADD CONSTRAINT constraint_name 
FOREIGN KEY (fk_columns) 
REFERENCES parent_table (parent_key_columns);

Giả sử, bạn muốn thêm ràng buộc FOREIGN KEY với tùy chọn ON DELETE CASCADE vào bảng hiện có, bạn cần làm theo các bước sau:

① Đầu tiên, loại bỏ các ràng buộc khóa ngoại hiện có:

ALTER TABLE bảng_tham_chiếu 
DROP CONSTRAINT constraint_fkey;

② Tiếp theo, thêm một ràng buộc FOREIGN KEY mới với action ON DELETE CASCADE:

ALTER TABLE bảng_tham_chiếu
ADD CONSTRAINT constraint_fk
FOREIGN KEY (fk_columns)
REFERENCES parent_table(parent_key_columns)
ON DELETE CASCADE;

Cảm ơn bạn đã theo dõi. Đừng ngần ngại hãy cùng thảo luận với chúng tôi!

Giới thiệu

Minh Hoàng

Xin chào, tôi là Hoàng Ngọc Minh, hiện đang làm BrSE, tại công ty Toyota, Nhật Bản. Những gì tôi viết trên blog này là những trải nghiệm thực tế tôi đã đúc rút ra được trong cuộc sống, quá trình học tập và làm việc. Các bài viết được biên tập một cách chi tiết, linh hoạt để giúp bạn đọc có thể tiếp cận một cách dễ dàng nhất. Hi vọng nó sẽ có ích hoặc mang lại một góc nhìn khác cho bạn[...]

Translate »