FOREIGN KEY (Khóa ngoại ) trong MySQL

FOREIGN KEY (Khóa ngoại ) trong MySQL
FOREIGN KEY (Khóa ngoại ) trong MySQL

Chức năng của FOREIGN KEY (Khóa ngoại ) trong MySQL

FOREIGN KEY (Khóa ngoại ) trong MySQL dùng để tham chiếu khóa ngoại của một bảng con đến khóa chính của bảng cha, nó ràng buộc nếu có giá trị ở bảng khóa ngoại thì bên khóa chính không thể xóa được.

Code FOREIGN KEY (Khóa ngoại ) trong MySQL

FOREIGN KEY (Khóa ngoại ) lúc CREATE TABLE trong MySQL

Khóa chính: Tạo tb_lop học có khóa chính là id

CREATE TABLE `tb_lophoc` (
  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `ten` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL
  ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
<?php
   $dbhost = 'localhost';
   $dbuser = 'webmoi_userdata'; // Tên username
   $dbpass = 'IhNRcn9n'; // Mật khẩu
   // Kết nối đến tên username
   $conn = mysql_connect($dbhost, $dbuser, $dbpass);
   if(! $conn ){
     die('Không kết nối được: ' . mysql_error());
   }
   // Chọn tên database
   mysql_select_db('webmoi_tendata');
   // Xét kiểu tiếng việt 
   mysql_query('SET NAMES "utf8"');
   
  // CREATE TABLE `tb_lophoc`
   echo "<b>CREATE TABLE `tb_lophoc`</b><br>";
   $sql ="CREATE TABLE `tb_lophoc` (
  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `ten` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL
  ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
  ";
  //Cột id: kiểu int giới hạn 11 ký tự, không cho phép null, PRIMARY KEY là tạo khóa chính, AUTO_INCREMENT là tự động tăng dần sau mỗi lần thêm một hàng
  // Cột ten: kiểu chữ varchar giới hạn 255 ký tự, kiểu utf-8, cho phép null
   $ketquamot = mysql_query($sql,$conn);
   if(!$ketquamot){
	  die('Không thể tạo bảng: ' . mysql_error());  
   }else{
	  echo "Tạo tb_lophoc thành công!"; 
   } 
   // Đóng kết nối database
   mysql_close($conn);
?>

Khóa ngoại: Tạo tb_hocsinh có khóa ngoại là idlophoc tham chiếu tới khóa chính id trong tb_lophoc

CREATE TABLE `tb_hocsinh` (
  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `ten` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `idlophoc` int(11) NOT NULL,
  FOREIGN KEY (idlophoc) REFERENCES tb_lophoc(id)  
  ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
<?php
   $dbhost = 'localhost';
   $dbuser = 'webmoi_userdata'; // Tên username
   $dbpass = 'IhNRcn9n'; // Mật khẩu
   // Kết nối đến tên username
   $conn = mysql_connect($dbhost, $dbuser, $dbpass);
   if(! $conn ){
     die('Không kết nối được: ' . mysql_error());
   }
   // Chọn tên database
   mysql_select_db('webmoi_tendata');
   // Xét kiểu tiếng việt 
   mysql_query('SET NAMES "utf8"');
   
  // CREATE TABLE `tb_hocsinh`
   echo "<b>CREATE TABLE `tb_hocsinh`</b><br>";
   $sql ="CREATE TABLE `tb_hocsinh` (
  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `ten` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `idlophoc` int(11) NOT NULL,
  FOREIGN KEY (idlophoc) REFERENCES tb_lophoc(id)  
  ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
  ";
  //Cột id: kiểu int giới hạn 11 ký tự, không cho phép null, PRIMARY KEY là tạo khóa chính, AUTO_INCREMENT là tự động tăng dần sau mỗi lần thêm một hàng
  // Cột ten: kiểu chữ varchar giới hạn 255 ký tự, kiểu utf-8, cho phép null
   $ketquamot = mysql_query($sql,$conn);
   if(!$ketquamot){
	  die('Không thể tạo bảng: ' . mysql_error());  
   }else{
	  echo "Tạo tb_hocsinh thành công!"; 
   } 
   // Đóng kết nối database
   mysql_close($conn);
?>

FOREIGN KEY (Khóa ngoại ) lúc CREATE TABLE trong MySQL

Tạo khóa ngoại không có đặt tên khóa ngoại, tb_hocsinh và tb_lophoc đã có, mình đặt tên khóa ngoại là KN_idlophoc:

ALTER TABLE tb_hocsinh ADD FOREIGN KEY (idlophoc) REFERENCES tb_lophoc(id);
<?php
   $dbhost = 'localhost';
   $dbuser = 'webmoi_userdata'; // Tên username
   $dbpass = 'IhNRcn9n'; // Mật khẩu
   // Kết nối đến tên username
   $conn = mysql_connect($dbhost, $dbuser, $dbpass);
   if(! $conn ){
     die('Không kết nối được: ' . mysql_error());
   }
   // Chọn tên database
   mysql_select_db('webmoi_tendata');
   // Xét kiểu tiếng việt 
   mysql_query('SET NAMES "utf8"');
   
  // ALTER TABLE `tb_hocsinh`
   echo "<b>ALTER TABLE `tb_hocsinh`</b><br>";
   $sql ="ALTER TABLE tb_hocsinh ADD FOREIGN KEY (idlophoc) REFERENCES tb_lophoc(id);";
   $ketquamot = mysql_query($sql,$conn);
   if(!$ketquamot){
	  die('Không thể ALTER TABLE: ' . mysql_error());  
   }else{
	  echo "ALTER TABLE tb_hocsinh thành công!"; 
   } 
   // Đóng kết nối database
   mysql_close($conn);
?>

Tạo khóa ngoại có đặt tên khóa ngoại, tb_hocsinh và tb_lophoc đã có:

ALTER TABLE tb_hocsinh ADD CONSTRAINT KN_idlophoc FOREIGN KEY (idlophoc) REFERENCES tb_lophoc(id);
<?php
   $dbhost = 'localhost';
   $dbuser = 'webmoi_userdata'; // Tên username
   $dbpass = 'IhNRcn9n'; // Mật khẩu
   // Kết nối đến tên username
   $conn = mysql_connect($dbhost, $dbuser, $dbpass);
   if(! $conn ){
     die('Không kết nối được: ' . mysql_error());
   }
   // Chọn tên database
   mysql_select_db('webmoi_tendata');
   // Xét kiểu tiếng việt 
   mysql_query('SET NAMES "utf8"');
   
  // ALTER TABLE `tb_hocsinh`
   echo "<b>ALTER TABLE `tb_hocsinh`</b><br>";
   $sql ="ALTER TABLE tb_hocsinh ADD CONSTRAINT KN_idlophoc FOREIGN KEY (idlophoc) REFERENCES tb_lophoc(id);";
   $ketquamot = mysql_query($sql,$conn);
   if(!$ketquamot){
	  die('Không thể ALTER TABLE: ' . mysql_error());  
   }else{
	  echo "ALTER TABLE tb_hocsinh thành công!"; 
   } 
   // Đóng kết nối database
   mysql_close($conn);
?>

Xóa tên khóa ngoại KN_idlophoc vừa đặt, nhiều phpmyadmin không cho xóa qua code:

ALTER TABLE tb_hocsinh DROP FOREIGN KEY KN_idlophoc;
<?php
   $dbhost = 'localhost';
   $dbuser = 'webmoi_userdata'; // Tên username
   $dbpass = 'IhNRcn9n'; // Mật khẩu
   // Kết nối đến tên username
   $conn = mysql_connect($dbhost, $dbuser, $dbpass);
   if(! $conn ){
     die('Không kết nối được: ' . mysql_error());
   }
   // Chọn tên database
   mysql_select_db('webmoi_tendata');
   // Xét kiểu tiếng việt 
   mysql_query('SET NAMES "utf8"');
   
  // ALTER TABLE `tb_hocsinh`
   echo "<b>ALTER TABLE `tb_hocsinh`</b><br>";
   $sql ="ALTER TABLE tb_hocsinh DROP FOREIGN KEY KN_idlophoc";
   $ketquamot = mysql_query($sql,$conn);
   if(!$ketquamot){
	  die('Không thể ALTER TABLE: ' . mysql_error());  
   }else{
	  echo "ALTER TABLE tb_hocsinh thành công!"; 
   } 
   // Đóng kết nối database
   mysql_close($conn);
?>

FOREIGN KEY kiểm soát dữ liệu giữa các bảng trong MySQL như thế nào?

FOREIGN KEY không chỉ dùng để liên kết các bảng mà còn giúp MySQL kiểm soát tính hợp lệ của dữ liệu giữa bảng con và bảng được tham chiếu. Nhờ đó, một bản ghi ở bảng con không thể tùy ý trỏ đến một bản ghi không tồn tại ở bảng cha.

Cơ chế này đặc biệt hữu ích với các hệ thống có quan hệ dữ liệu như khách hàng - đơn hàng, danh mục - sản phẩm hoặc phòng ban - nhân viên. Khi dữ liệu liên quan bị thêm, sửa hoặc xóa, MySQL sẽ kiểm tra ràng buộc FOREIGN KEY trước khi thực hiện thao tác.

Thêm dữ liệu không tồn tại trong bảng được tham chiếu

Khi thêm một bản ghi vào bảng con, giá trị của cột FOREIGN KEY phải tồn tại ở cột được tham chiếu trong bảng cha. Nếu giá trị không tồn tại, MySQL sẽ từ chối thao tác để tránh tạo ra dữ liệu liên kết không hợp lệ.

Ví dụ, bảng orders sử dụng customer_id để tham chiếu đến bảng customers. Nếu chưa có khách hàng mang mã 100, câu lệnh sau sẽ không thể thêm đơn hàng:

INSERT INTO orders (customer_id, total)
VALUES (100, 500000);

Cách kiểm soát này giúp tránh trường hợp đơn hàng tồn tại nhưng không xác định được khách hàng tương ứng. Khi cần thêm dữ liệu, nên tạo bản ghi ở bảng cha trước rồi mới tạo dữ liệu ở bảng con.

Xóa dữ liệu đang được bảng khác tham chiếu

MySQL cũng kiểm tra khi xóa một bản ghi ở bảng cha. Nếu bản ghi đó đang được bảng con tham chiếu và khóa ngoại không cho phép xóa theo dây chuyền, thao tác sẽ bị từ chối.

Chẳng hạn, một khách hàng đang có đơn hàng thì việc xóa khách hàng có thể làm mất mối liên hệ giữa hai bảng. Khi đó, MySQL bảo vệ dữ liệu bằng cách không cho phép xóa bản ghi đang được tham chiếu.

DELETE FROM customers
WHERE id = 10;

Thay vì xóa trực tiếp, cần xử lý các bản ghi liên quan theo quy tắc phù hợp với thiết kế dữ liệu. Đây là một trong những lý do nên xác định rõ hành vi của FOREIGN KEY ngay từ khi xây dựng cấu trúc database.

Cập nhật dữ liệu có liên quan đến khóa ngoại

Khi thay đổi giá trị của cột được tham chiếu hoặc cột FOREIGN KEY, MySQL cũng kiểm tra ràng buộc giữa hai bảng. Giá trị mới phải bảo đảm quan hệ dữ liệu vẫn hợp lệ.

Ví dụ, không thể tùy ý đổi customer_id của một đơn hàng sang một mã khách hàng chưa tồn tại:

UPDATE orders
SET customer_id = 200
WHERE id = 15;

Nếu khách hàng có mã 200 chưa tồn tại trong bảng customers, câu lệnh sẽ bị từ chối. Điều này giúp hạn chế dữ liệu mồ côi và giữ cho mối quan hệ giữa các bảng luôn nhất quán.

Sử dụng ON DELETE và ON UPDATE với FOREIGN KEY

Để xác định MySQL phải xử lý dữ liệu liên quan như thế nào khi bản ghi ở bảng cha bị xóa hoặc cập nhật, có thể sử dụng ON DELETEON UPDATE. Đây là cách chủ động thiết lập hành vi của khóa ngoại thay vì chỉ ngăn thao tác gây vi phạm ràng buộc.

Một số lựa chọn thường gặp gồm CASCADE, SET NULLRESTRICT. Ví dụ, CASCADE cho phép thao tác ở bảng cha được áp dụng tiếp cho các bản ghi liên quan ở bảng con:

CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT,
    total DECIMAL(12,2),
    FOREIGN KEY (customer_id)
        REFERENCES customers(id)
        ON DELETE CASCADE
        ON UPDATE CASCADE
);

Với cấu hình trên, khi một khách hàng bị xóa, các đơn hàng liên quan cũng có thể bị xóa theo. Vì vậy, CASCADE nên được sử dụng khi việc xóa dữ liệu liên đới là đúng với nghiệp vụ; nếu dữ liệu cần được bảo toàn, nên chọn quy tắc phù hợp khác.

Lời kết

Cảm ơn các bạn đã tham khảo bài viết FOREIGN KEY (Khóa ngoại ) trong MySQL.

Tải file database .sql về nếu muốn kiểm tra hoặc thực hành Tải về.

  • 0 Bình luận
CEO Bùi Tấn Lực | Founder Web Mới
Bùi Tấn Lực
Tìm hiểu về CEO Bùi Tấn Lực, Founder Web Mới với nhiều năm kinh nghiệm trong lĩnh vực phát triển website, SEO và chia sẻ kiến thức công nghệ
Chia sẻ nội dung đánh giá của bạn về FOREIGN KEY (Khóa ngoại ) trong MySQL
Email, Điện thoại của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *
Đánh giá của bạn
Tên *
Email
Số điện thoại *
Bình luận, Hỏi đáp
Đăng ký tư vấn thiết kế website
Tìm hiểu 1 năm không bằng lắng nghe 1 câu tư vấn