Trong SQL Server, bạn có thể tạo CHECK
ràng buộc trong bảng để chỉ định các giá trị dữ liệu được chấp nhận trong một hoặc nhiều cột.
Nếu một bảng có CHECK
ràng buộc về nó và bạn cố gắng cung cấp dữ liệu không tuân theo CHECK
ràng buộc, hoạt động sẽ không thành công với một lỗi.
Điều này giúp duy trì tính toàn vẹn của dữ liệu, vì nó giúp ngăn dữ liệu không hợp lệ xâm nhập vào cơ sở dữ liệu.
Khi bạn tạo CHECK
ràng buộc, bạn cung cấp một biểu thức logic trả về TRUE
hoặc FALSE
. Biểu thức logic này được sử dụng để kiểm tra dữ liệu.
CHECK
các ràng buộc tương tự như các ràng buộc khóa ngoại vì chúng kiểm soát các giá trị được đặt trong một cột. Tuy nhiên, sự khác biệt là ở cách chúng xác định giá trị nào là hợp lệ:Ràng buộc khóa ngoại lấy danh sách các giá trị hợp lệ từ một bảng khác, trong khi CHECK
các ràng buộc xác định các giá trị hợp lệ từ một biểu thức logic.
Các ràng buộc có thể được xác định ở cấp cột hoặc cấp bảng. Ràng buộc cấp cột chỉ áp dụng cho dữ liệu trong cột đó. Ràng buộc cấp bảng áp dụng cho toàn bộ hàng và kiểm tra dữ liệu từ nhiều cột.
Dưới đây là các ví dụ về cách tạo CHECK
cấp cột và cấp bảng ràng buộc.
Ví dụ 1 - Tạo Ràng buộc KIỂM TRA Cấp Cột
Dưới đây là ví dụ về cách tạo CHECK
cấp cột cơ bản tại thời điểm tạo bảng.
CREATE TABLE ConstraintTest ( ConstraintTestId int IDENTITY(1,1) NOT NULL PRIMARY KEY, Price smallmoney NOT NULL, CONSTRAINT chkPrice CHECK (Price > 0) );
Trong trường hợp này, CHECK
ràng buộc chỉ định rằng tất cả dữ liệu trong Price
cột phải lớn hơn 0. Nói cách khác, giá không được bằng 0 và không được âm. Đây là ràng buộc cấp cột vì nó áp dụng cho dữ liệu trong một cột.
Bởi vì đây là một ràng buộc ở cấp độ cột, tôi có thể định nghĩa nó là một phần của cột (không có dấu phẩy). Vì vậy, tôi có thể đã làm điều này:
CREATE TABLE ConstraintTest ( ConstraintTestId int IDENTITY(1,1) NOT NULL PRIMARY KEY, Price smallmoney NOT NULL CONSTRAINT chkPrice CHECK (Price > 0) );
Dù bằng cách nào, hãy cố gắng chèn một giá trị không hợp lệ:
INSERT INTO ConstraintTest ( Price ) VALUES ( 0 );
Kết quả:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkPrice". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'Price'.
Ví dụ 2 - Thêm các cột khác và một ràng buộc kiểm tra ở cấp độ cột khác
Hãy thêm một số cột khác vào bảng của chúng tôi và sau đó thêm một cột khác CHECK
ràng buộc.
ALTER TABLE ConstraintTest ADD TeamSize tinyint NOT NULL, StartDate date NOT NULL, EndDate date NOT NULL, CONSTRAINT chkTeamSize CHECK (TeamSize >= 3 AND TeamSize <= 15) ;
Một trong các cột mới ghi lại số lượng thành viên trong nhóm. Trong trường hợp này, quy tắc kinh doanh là một nhóm phải có ít nhất 3 thành viên, nhưng không quá 15. Do đó, cơ sở dữ liệu sẽ ngăn chặn tình huống một nhóm có ít hơn 3 thành viên hoặc nhiều hơn 15.
Hãy thử chèn một giá trị không hợp lệ:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 2, '2020-01-01', '1900-02-02' );
Kết quả:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkTeamSize". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'TeamSize'.
Ví dụ 3 - Thêm Ràng buộc KIỂM TRA Cấp Bảng
Bây giờ, hãy thêm một ràng buộc cấp bảng. Thao tác này sẽ kiểm tra dữ liệu trong hai cột.
Nhân tiện, bạn không phải thêm một cột khác để thêm CHECK
hạn chế. Bạn chỉ cần thêm ràng buộc vào chính nó.
Ví dụ:
ALTER TABLE ConstraintTest ADD CONSTRAINT chkValidEndDate CHECK (EndDate >= StartDate) ;
Trong trường hợp này, tôi thêm một ràng buộc để đảm bảo rằng ngày kết thúc không bao giờ có thể sớm hơn ngày bắt đầu. Đây là kiểm tra dữ liệu trên hai cột và do đó là một ràng buộc cấp bảng.
Cố gắng chèn một giá trị không hợp lệ:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 3, '2020-01-01', '1900-02-02' );
Kết quả:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkValidEndDate". The conflict occurred in database "Test", table "dbo.ConstraintTest".
Lưu ý rằng để kiểm tra ràng buộc này, tôi phải tăng số thành viên trong nhóm lên 3 để ngăn ràng buộc trước đó không được kích hoạt trước (CHECK
các ràng buộc được xác thực theo thứ tự chúng được tạo).
Ví dụ 4 - Thay đổi Ràng buộc KIỂM TRA
Bạn thực sự không thể thay đổi một CHECK
hạn chế. Nếu bạn cần thay đổi nó, bạn sẽ cần bỏ nó và tạo nó với định nghĩa mới.
Ví dụ:
ALTER TABLE ConstraintTest DROP CONSTRAINT chkTeamSize; ALTER TABLE ConstraintTest ADD CONSTRAINT chkTeamSize CHECK (TeamSize >= 5 AND TeamSize <= 20) ;
Như đã đề cập, CHECK
các ràng buộc được xác thực theo thứ tự chúng được tạo, vì vậy điều này có thể ảnh hưởng đến lỗi nào được phát hiện trước.
Do đó, trong trường hợp này, nếu tôi cố gắng chèn một giá trị không hợp lệ (và bao gồm cả những ngày không hợp lệ), thì những ngày không hợp lệ sẽ bị bắt trước:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 4, '2020-01-01', '1900-02-02' );
Kết quả:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkValidEndDate". The conflict occurred in database "Test", table "dbo.ConstraintTest".
Vì vậy, để kiểm tra ràng buộc mới nhất của tôi, trước tiên tôi cần phải khắc phục vấn đề ngày tháng:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 4, '2020-01-01', '2020-02-02' );
Kết quả:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkTeamSize". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'TeamSize'.
Vì vậy, ràng buộc mới nhất của tôi đang hoạt động như mong đợi.
Ví dụ 5 - Ràng buộc KIỂM TRA và Cột IDENTITY
Vì vậy, bây giờ chúng tôi đã kiểm tra các ràng buộc, hãy tiếp tục và chèn dữ liệu hợp lệ:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 5, '2020-01-01', '2020-02-02' );
Kết quả:
+--------------------+---------+------------+-------------+------------+ | ConstraintTestId | Price | TeamSize | StartDate | EndDate | |--------------------+---------+------------+-------------+------------| | 13 | 1.0000 | 5 | 2020-01-01 | 2020-02-02 | +--------------------+---------+------------+-------------+------------+
Cuối cùng, chúng tôi nhận được một chèn thành công.
Tuy nhiên, bạn sẽ nhận thấy rằng IDENTITY
cột đã tăng lên 13.
Hãy nhớ rằng khi tôi tạo bảng lần đầu tiên, tôi đã xác định ConstraintTestId
cột để sử dụng IDENTITY(1,1)
, có nghĩa là nó phải bắt đầu từ 1 và tự động tăng lên 1 với mỗi lần chèn hàng.
Nhưng bây giờ cuối cùng tôi đã chèn hàng đầu tiên của mình, giá trị đã là 13. Đó là do IDENTITY
cột được tăng lên ngay cả khi CHECK
ràng buộc gây ra INSERT
hoạt động không thành công.
Lưu ý rằng tôi đã thực hiện thêm một số lần chèn không thành công trong khi đưa ra các ví dụ cho bài viết này, vì vậy giá trị đã tăng lên một giá trị cao hơn những gì bạn sẽ nhận được nếu bạn chỉ cần làm theo từng bước với bài viết này.
Trong mọi trường hợp, hãy thực hiện một lần chèn không thành công cuối cùng, sau đó thực hiện một lần chèn thành công để xác nhận điều này.
Chèn không thành công:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 2, 4, '2020-01-02', '2020-02-03' );
Kết quả:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkTeamSize". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'TeamSize'.
Chèn thành công:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 2, 6, '2020-01-02', '2020-02-03' ); SELECT * FROM ConstraintTest;
Kết quả:
+--------------------+---------+------------+-------------+------------+ | ConstraintTestId | Price | TeamSize | StartDate | EndDate | |--------------------+---------+------------+-------------+------------| | 13 | 1.0000 | 5 | 2020-01-01 | 2020-02-02 | | 15 | 2.0000 | 6 | 2020-01-02 | 2020-02-03 | +--------------------+---------+------------+-------------+------------+
Chúng ta có thể thấy rằng IDENTITY
cột nhảy từ 13 đến 15, vì vậy nó rõ ràng tăng lên trong quá trình chèn không thành công.
Một số hạn chế của Ràng buộc CHECK
Dưới đây là một số hạn chế cần lưu ý khi làm việc với CHECK
ràng buộc:
- Điều kiện tìm kiếm phải đánh giá thành biểu thức Boolean và không thể tham chiếu đến bảng khác.
- Biểu thức không được chứa các kiểu dữ liệu bí danh.
-
CHECK
không thể xác định ràng buộc trên văn bản , ntext hoặc hình ảnh cột.