Khóa chính và khóa ngoại trong SQLite với các ví dụ

⚡ Tóm tắt thông minh

Khóa chính và khóa ngoại trong SQLite Đảm bảo tính toàn vẹn dữ liệu bằng cách xác định duy nhất từng hàng và liên kết các bảng liên quan, đảm bảo các giá trị được tham chiếu luôn tồn tại và ngăn ngừa các bản ghi trùng lặp, rỗng hoặc mồ côi trong cơ sở dữ liệu quan hệ.

  • 🔑 Khóa chính: Khóa chính xác định duy nhất mỗi hàng và các giá trị của nó phải là duy nhất và không bao giờ là null.
  • 🧩 Tổ hợp phím: Việc kết hợp hai hoặc nhiều cột tạo thành khóa chính phức hợp khi không có cột nào là duy nhất.
  • 🔗 Khóa ngoài: Khóa ngoại tham chiếu đến khóa của bảng cha và đảm bảo tính toàn vẹn tham chiếu giữa các bảng có liên quan.
  • ⚙️ Kích hoạt tính năng thực thi: SQLite Theo mặc định, lệnh này vô hiệu hóa khóa ngoại, vì vậy hãy chạy PRAGMA foreign_keys = ON để kích hoạt chúng.
  • 🧱 Ràng buộc cột: Các quy tắc NOT NULL, DEFAULT, UNIQUE và CHECK xác thực các giá trị trước khi chúng được nhập vào một cột.
  • 🤖 Hỗ trợ AI: Các trợ lý chuyển văn bản thành SQL bằng AI và GitHub Copilot tạo ra các câu lệnh SQL khóa và ràng buộc từ tiếng Anh thông thường.

Khóa chính và khóa ngoại trong SQLite

Các phần dưới đây giải thích SQLite Trình bày chi tiết các ràng buộc, bắt đầu với KHÓA CHÍNH và KHÓA NGOẠI dùng để định nghĩa và kết nối các bảng, và bao gồm các quy tắc KHÔNG ĐƯỢC NULL, MẶC ĐỊNH, DUY NHẤT và KIỂM TRA để xác thực dữ liệu trong mỗi cột.

SQLite Những ràng buộc

Các ràng buộc cột áp đặt các quy tắc lên các giá trị được chèn vào một cột để xác thực dữ liệu. Các ràng buộc này được định nghĩa khi tạo bảng, bên trong phần định nghĩa cột. Chúng giúp dữ liệu được lưu trữ nhất quán và chính xác bằng cách loại bỏ các giá trị vi phạm các quy tắc bạn đặt ra, chẳng hạn như các giá trị trùng lặp, giá trị null hoặc các giá trị không tồn tại trong bảng liên quan.

SQLite Khóa chính

Tất cả các giá trị trong cột khóa chính phải là duy nhất và không được rỗng. Khóa chính xác định duy nhất mỗi hàng trong bảng.

Khóa chính có thể được áp dụng cho chỉ một cột hoặc cho sự kết hợp của nhiều cột. Trong trường hợp thứ hai, sự kết hợp các giá trị của các cột phải là duy nhất đối với tất cả các hàng trong bảng.

Cú pháp:

Có nhiều cách khác nhau để định nghĩa khóa chính trên một bảng:

Trong chính định nghĩa cột:

ColumnName INTEGER NOT NULL PRIMARY KEY;

Là một định nghĩa riêng:

PRIMARY KEY(ColumnName);

Để tạo tổ hợp các cột làm khóa chính:

PRIMARY KEY(ColumnName1, ColumnName2);

SQLite Các ràng buộc NOT NULL, DEFAULT, UNIQUE và CHECK

Ngoài khóa chính, SQLite Cung cấp một số ràng buộc cột để xác thực các giá trị được nhập vào bảng. Các ràng buộc NOT NULL, DEFAULT, UNIQUE và CHECK được định nghĩa trong phần định nghĩa cột, và mỗi ràng buộc đều thực thi một quy tắc cụ thể đối với cột đó. loại dữ liệu và các giá trị.

Ràng buộc KHÔNG NULL

SQLite Ràng buộc NOT NULL ngăn không cho một cột có giá trị null:

ColumnName INTEGER  NOT NULL;

Ràng buộc MẶC ĐỊNH

Với SQLite Ràng buộc DEFAULT: nếu bạn không nhập bất kỳ giá trị nào vào một cột, giá trị mặc định sẽ được nhập thay thế.

Ví dụ:

ColumnName INTEGER DEFAULT 0;

Nếu bạn viết câu lệnh INSERT mà không chỉ định giá trị cho cột đó, cột sẽ có giá trị là 0.

Hạn chế duy nhất

SQLite Ràng buộc UNIQUE ngăn chặn việc trùng lặp giá trị giữa tất cả các giá trị trong cột.

Ví dụ:

EmployeeId INTEGER NOT NULL UNIQUE;

Điều này đảm bảo giá trị “EmployeeId” là duy nhất; không cho phép các giá trị trùng lặp. Lưu ý rằng điều này chỉ áp dụng cho các giá trị trong cột “EmployeeId”.

KIỂM TRA Ràng buộc

SQLite Ràng buộc CHECK đặt ra một điều kiện để kiểm tra giá trị được chèn vào. Nếu giá trị không khớp với điều kiện, nó sẽ không được chèn.

Quantity INTEGER NOT NULL CHECK(Quantity > 10);

Bạn không thể nhập giá trị nhỏ hơn 10 vào cột “Số lượng”.

SQLite chính nước ngoài

SQLite Khóa ngoại là một ràng buộc xác minh sự tồn tại của một giá trị có trong một bảng ở một bảng khác có quan hệ với bảng đầu tiên nơi khóa ngoại được định nghĩa.

Khi làm việc với nhiều bảng, có những trường hợp hai bảng liên kết với nhau thông qua một cột chung. Nếu bạn muốn đảm bảo rằng giá trị được chèn vào một trong hai bảng phải tồn tại trong cột của bảng kia, thì bạn nên sử dụng ràng buộc khóa ngoại trên cột chung đó.

Trong trường hợp này, khi bạn cố gắng chèn một giá trị vào cột đó, khóa ngoại sẽ đảm bảo rằng giá trị được chèn tồn tại trong cột của bảng được tham chiếu.

Lưu ý rằng các ràng buộc khóa ngoại không được bật theo mặc định trong SQLiteBạn cần kích hoạt chúng trước bằng cách chạy lệnh sau:

PRAGMA foreign_keys = ON;

Ràng buộc khóa ngoại được đưa vào SQLite bắt đầu từ phiên bản 3.6.19.

Ví dụ về SQLite chính nước ngoài

Giả sử chúng ta có hai bảng: Sinh viên và Khoa.

Bảng Students chứa danh sách sinh viên, và bảng Departments chứa danh sách các khoa. Mỗi sinh viên thuộc về một khoa; nghĩa là, mỗi sinh viên có một cột departmentId.

Bây giờ chúng ta sẽ xem cách ràng buộc khóa ngoại có thể hữu ích để đảm bảo rằng giá trị của mã phòng ban trong bảng Sinh viên phải tồn tại trong bảng Phòng ban.

Vì vậy, nếu chúng ta tạo ràng buộc khóa ngoại trên DepartmentId trong bảng Students, thì mỗi departmentId được chèn vào phải có mặt trong bảng Departments.

CREATE TABLE [Departments] (
	[DepartmentId] INTEGER  NOT NULL PRIMARY KEY AUTOINCREMENT,
	[DepartmentName] NVARCHAR(50)  NULL
);
CREATE TABLE [Students] (
	[StudentId] INTEGER  PRIMARY KEY AUTOINCREMENT NOT NULL,
	[StudentName] NVARCHAR(50)  NULL,
	[DepartmentId] INTEGER  NOT NULL,
	[DateOfBirth] DATE  NULL,
	FOREIGN KEY(DepartmentId) REFERENCES Departments(DepartmentId)
);

Để kiểm tra cách các ràng buộc khóa ngoại có thể ngăn chặn việc chèn một phần tử hoặc giá trị chưa được định nghĩa vào một bảng có quan hệ với bảng khác, chúng ta sẽ xem xét ví dụ sau.

Trong ví dụ này, bảng Departments có mối quan hệ khóa ngoại với bảng Students, vì vậy bất kỳ giá trị departmentId nào được chèn vào bảng Students đều phải tồn tại trong bảng Departments. Nếu bạn cố gắng chèn một giá trị departmentId không tồn tại trong bảng Departments, ràng buộc khóa ngoại sẽ ngăn bạn thực hiện điều đó.

Chúng ta hãy thêm hai phòng ban, “CNTT” và “Nghệ thuật”, vào bảng Phòng ban với các thao tác sau: Truy vấn INSERT:

INSERT INTO Departments VALUES(1, 'IT');
INSERT INTO Departments VALUES(2, 'Arts');

Hai câu lệnh này sẽ chèn hai phòng ban vào bảng Departments. Bạn có thể xác nhận việc hai giá trị đã được chèn bằng cách chạy truy vấn “SELECT * FROM Departments” sau đó:

Kết quả truy vấn SELECT hiển thị các khoa CNTT và Nghệ thuật trong SQLite

Sau đó, hãy thử thêm một sinh viên mới với mã phòng ban (departmentId) không tồn tại trong bảng Departments:

INSERT INTO Students(StudentName,DepartmentId) VALUES('John', 5);

Dòng dữ liệu sẽ không được chèn và bạn sẽ nhận được thông báo lỗi: Ràng buộc khóa ngoại không thành công.

SQLite Thông báo lỗi: Không thể thực hiện ràng buộc khóa ngoại.

Sự khác biệt giữa khóa chính và khóa ngoại trong SQLite

Khóa chính và khóa ngoại đều giúp duy trì tính toàn vẹn dữ liệu, nhưng chúng đóng vai trò khác nhau. Khóa chính xác định các hàng trong một bảng duy nhất, trong khi khóa ngoại liên kết các hàng giữa hai bảng có liên quan. Bảng dưới đây tóm tắt những điểm khác biệt chính.

Cơ sở Khóa chính chính nước ngoài
Mục đích Xác định duy nhất từng hàng trong bảng tương ứng. Tham chiếu đến khóa chính của bảng khác để liên kết chúng.
Tính độc đáo Các giá trị phải là duy nhất Các giá trị có thể lặp lại, do đó nhiều hàng con có thể chia sẻ một hàng cha.
Giá trị rỗng Không được phép là null Có thể là null khi mối quan hệ là tùy chọn.
Số lượng mỗi bàn Mỗi bảng chỉ có một khóa chính. Một bảng có thể có nhiều khóa ngoại.
Lập chỉ mục Được lập chỉ mục tự động Không được lập chỉ mục tự động; hãy thêm một chỉ mục để cải thiện hiệu suất.

Trong ví dụ về Sinh viên và Khoa, DepartmentId là khóa chính của bảng Khoa và là khóa ngoại trong bảng Sinh viên, liên kết mỗi sinh viên với một khoa hợp lệ.

SQLite Khóa chính tổng hợp

Khóa chính phức hợp là khóa chính được tạo thành từ hai hoặc nhiều cột. Nó được sử dụng khi không có cột nào là duy nhất khi đứng riêng lẻ, nhưng sự kết hợp của các cột lại là duy nhất đối với mọi hàng. SQLite Coi các giá trị kết hợp như một khóa duy nhất.

Ví dụ, bảng đăng ký có thể cho phép cùng một sinh viên tham gia nhiều khóa học và cùng một khóa học cho nhiều sinh viên, nhưng mỗi cặp sinh viên-khóa học chỉ được xuất hiện một lần:

CREATE TABLE Enrollments (
	StudentId INTEGER NOT NULL,
	CourseId INTEGER NOT NULL,
	Grade TEXT,
	PRIMARY KEY (StudentId, CourseId)
);

Ở đây, cả StudentId và CourseId đều không duy nhất khi đứng riêng lẻ, nhưng cặp (StudentId, CourseId) thì duy nhất, vì vậy cùng một sinh viên không thể đăng ký cùng một khóa học hai lần. Hãy lưu ý những điểm sau khi sử dụng khóa tổng hợp:

  • Sử dụng khóa tổng hợp khi một cột đơn không thể xác định duy nhất một hàng.
  • Mỗi cột trong khóa tổng hợp đều tuân theo các quy tắc của khóa chính, do đó giá trị kết hợp phải là duy nhất và không được rỗng.
  • Khóa tổng hợp được viết dưới dạng một mệnh đề PRIMARY KEY riêng biệt ở cấp độ bảng, chứ không phải nằm trong định nghĩa của một cột duy nhất.

SQLite Các thao tác khóa ngoại: ON DELETE và ON UPDATE

Khóa ngoại cũng có thể kiểm soát những gì xảy ra với các hàng con khi hàng cha mà chúng tham chiếu bị xóa hoặc cập nhật. Các hành động tham chiếu này được thêm vào bằng các mệnh đề ON DELETE và ON UPDATE khi bạn định nghĩa khóa ngoại. SQLite Hỗ trợ năm hành động:

  • KHÔNG CÓ HÀNH ĐỘNG — hành động mặc định, sẽ báo lỗi nếu các hàng con vẫn tham chiếu đến hàng cha.
  • HẠN CHẾ — Ngăn chặn việc xóa hoặc cập nhật ngay lập tức, trước khi bất kỳ thay đổi nào khác được thực thi.
  • Đặt vô giá trị — đặt cột khóa ngoại con thành null.
  • THIẾT BỊ DEFAULT — đặt cột khóa ngoại con về giá trị mặc định đã khai báo.
  • CASCADE — Áp dụng cùng một thay đổi cho các hàng con, vì vậy việc xóa một hàng cha sẽ xóa luôn các hàng con của nó.

Ví dụ dưới đây tạo lại bảng Sinh viên sao cho việc xóa một khoa sẽ tự động xóa sinh viên thuộc khoa đó, và việc cập nhật ID khoa sẽ cập nhật thông tin sinh viên tương ứng:

CREATE TABLE Students (
	StudentId INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
	StudentName NVARCHAR(50) NULL,
	DepartmentId INTEGER NOT NULL,
	FOREIGN KEY(DepartmentId) REFERENCES Departments(DepartmentId)
		ON DELETE CASCADE
		ON UPDATE CASCADE
);

Hãy nhớ rằng các thao tác tham chiếu chỉ chạy khi hỗ trợ khóa ngoại được bật, vì vậy hãy chạy lệnh PRAGMA foreign_keys = ON khi bắt đầu mỗi kết nối. Nếu không, SQLite Phân tích các điều khoản ON DELETE và ON UPDATE nhưng không thực thi chúng.

Câu Hỏi Thường Gặp

Đúng vậy. Khi một cột được khai báo chính xác là INTEGER PRIMARY KEY, nó sẽ trở thành bí danh cho rowid tích hợp sẵn của bảng. SQLite Nó không được lưu trữ dưới dạng chỉ mục riêng biệt, do đó việc tìm kiếm theo khóa đó rất nhanh và không tốn thêm dung lượng lưu trữ.

Chức năng thực thi khóa ngoại được tắt theo mặc định để duy trì khả năng tương thích ngược với các cơ sở dữ liệu và tập lệnh cũ được viết trước phiên bản 3.6.19. Mỗi kết nối cơ sở dữ liệu phải chạy lệnh PRAGMA foreign_keys = ON trước khi thực hiện. SQLite Bắt đầu kiểm tra các ràng buộc khóa ngoại.

SQLite Chỉ mục được tạo tự động cho các khóa chính và cột UNIQUE, nhưng không tạo chỉ mục cho các cột khóa ngoại. Vì cột con được đọc trong mỗi lần kiểm tra ràng buộc, nên để tối ưu hiệu suất, bạn nên tạo chỉ mục riêng cho từng cột khóa ngoại.

Không. ALTER TABLE trong SQLite Không thể thêm khóa chính hoặc khóa ngoại vào bảng hiện có. Bạn phải đổi tên bảng cũ, tạo bảng mới với khóa đã được định nghĩa, sao chép các hàng bằng câu lệnh INSERT SELECT, sau đó xóa bảng cũ.

Khóa chính kiểu INTEGER đơn giản gán ID tiếp theo là ID cao hơn ID hàng lớn nhất hiện có và có thể sử dụng lại ID sau khi xóa. TỰ ĐỘNG TĂNG tracks là ID cao nhất từng được sử dụng trong sqlite_sequence và không bao giờ sử dụng lại một giá trị nào, với một chút chi phí về hiệu năng.

Lỗi này xuất hiện khi bạn chèn hoặc cập nhật một hàng con mà giá trị khóa ngoại của nó không có hàng tương ứng trong bảng cha, hoặc khi bạn xóa một hàng cha vẫn còn các hàng con. Hãy chèn bản ghi cha trước.

Đúng vậy. Các công cụ hỗ trợ chuyển đổi văn bản thành SQL bằng AI sẽ chuyển đổi mô tả bằng tiếng Anh thông thường về các bảng của bạn thành các câu lệnh CREATE TABLE với các mệnh đề PRIMARY KEY và FOREIGN KEY. Việc cung cấp lược đồ hiện có sẽ cải thiện độ chính xác, và SQL được tạo ra luôn cần được xem xét lại trước khi chạy trên dữ liệu thực.

Vâng. Trợ lý GitHub đề xuất sử dụng mã CREATE TABLE với PRIMARY KEY, FOREIGN KEY và các ràng buộc khác trực tiếp trong các trình soạn thảo như... VS CodeNó đọc lược đồ và các bản di chuyển hiện có của bạn, vì vậy các gợi ý hoàn thành của nó sẽ sử dụng lại tên bảng và cột thực của bạn.

Tóm tắt bài viết này với: