Nếu bạn rơi vào trường hợp cần bật lại CHECK
ràng buộc trước đó đã bị vô hiệu hóa, bạn chắc chắn nên đảm bảo rằng bạn biết mình đang làm gì.
Đặc biệt, bạn nên hiểu sự khác biệt giữa WITH NOCHECK
và WITH CHECK
đối số.
Các đối số này có thể được sử dụng tại thời điểm bạn kích hoạt ràng buộc. Chúng chỉ định xem dữ liệu hiện có có được xác thực hay không dựa trên CHECK
được bật lại (hoặc mới được thêm vào) của bạn hạn chế. Về cơ bản, bạn có tùy chọn kiểm tra tất cả dữ liệu hiện có để tìm bất kỳ vi phạm nào đối với ràng buộc. Nếu bạn không chỉ định bất kỳ điều gì, thì dữ liệu hiện có sẽ không đã kiểm tra. Đó là lý do tại sao điều quan trọng là phải hiểu cách hoạt động của nó.
Nhân tiện, các đối số này cũng áp dụng cho các ràng buộc khóa ngoại.
Như bạn có thể mong đợi, WITH CHECK
chỉ định rằng dữ liệu hiện có được xác thực và WITH NOCHECK
xác định rằng nó không phải là. Giá trị mặc định là WITH NOCHECK
.
Nếu bạn sử dụng WITH NOCHECK
, ràng buộc sẽ được gắn cờ là không đáng tin cậy. Trên thực tế, nó bị gắn cờ là không đáng tin cậy khi bạn tắt ràng buộc. Nhưng khi bạn bật lại nó, nó sẽ vẫn không đáng tin cậy trừ khi bạn sử dụng WITH CHECK
. Nói cách khác, nếu bạn muốn khẳng định lại “độ tin cậy” của nó, bạn phải chỉ định rõ ràng điều này.
Nói cách khác:
- Khi bạn sử dụng
WITH NOCHECK
, ràng buộc sẽ vẫn không đáng tin cậy. - Khi bạn sử dụng
WITH CHECK
nó sẽ trở nên đáng tin cậy, nhưng chỉ khi tất cả dữ liệu hiện có tuân theo ràng buộc. Nếu bất kỳ dữ liệu hiện có nào vi phạm giới hạn, thì ràng buộc đó sẽ không được bật và bạn sẽ nhận được thông báo lỗi.
Tất nhiên, khi tôi nói “tất cả dữ liệu hiện có”, tôi chỉ đề cập đến dữ liệu mà ràng buộc áp dụng.
Có thể có tình huống bạn cố tình vô hiệu hóa một ràng buộc vì bạn phải nhập dữ liệu vi phạm ràng buộc. Trong những trường hợp như vậy, nếu dữ liệu không hợp lệ phải vẫn còn trong cơ sở dữ liệu, bạn sẽ cần sử dụng WITH NOCHECK
nếu bạn muốn kích hoạt lại ràng buộc. Điều này sẽ cho phép bạn kích hoạt ràng buộc mà không có bất kỳ dữ liệu hiện có nào cản trở.
Dưới đây là các ví dụ chứng minh điều này.
Ví dụ 1 - Xem lại Ràng buộc KIỂM TRA
Đầu tiên, hãy sử dụng sys.check_constraints
để xem tất cả CHECK
các ràng buộc trong cơ sở dữ liệu hiện tại.
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Kết quả:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Chúng ta có thể thấy rằng tất cả chúng đều được bật và đáng tin cậy (vì chúng đều có số 0 trong is_disabled và is_not_trusted cột).
Đối với bài viết này, tôi sẽ tắt và bật lại chkJobTitle ràng buộc.
Ví dụ 2 - Tắt Ràng buộc
Ở đây, tôi tắt chkJobTitle ràng buộc:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Đã xong.
Bây giờ chúng ta hãy xem xét lại tất cả các ràng buộc:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Kết quả:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 1 | 1 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Chúng tôi có thể thấy rằng nó đã bị vô hiệu hóa (vì is_disabled của nó cột được đặt thành 1 ).
Bạn có thể nhận thấy rằng
is_not_trusted
cột cũng được đặt thành
1
. Điều này cho thấy rằng CHECK
ràng buộc chưa được hệ thống xác minh cho tất cả các hàng.
Như đã đề cập, CHECK
ràng buộc chỉ có thể được tin cậy nếu tất cả dữ liệu đã vượt qua thành công các điều kiện của ràng buộc. Khi chúng tôi vô hiệu hóa một ràng buộc, điều này sẽ mở ra khả năng dữ liệu không hợp lệ vào cơ sở dữ liệu. Do đó, chúng tôi không thể chắc chắn 100% rằng tất cả dữ liệu đều hợp lệ, do đó ràng buộc bị gắn cờ là không đáng tin cậy.
Cách để đảm bảo ràng buộc được tin cậy trở lại là bật lại nó bằng cách sử dụng WITH CHECK
lý lẽ. Điều này sẽ khiến ràng buộc kiểm tra tất cả dữ liệu trước khi nó được bật lại. Nếu bất kỳ dữ liệu nào không hợp lệ, dữ liệu đó sẽ không thể được kích hoạt lại. Bạn sẽ cần cập nhật dữ liệu để dữ liệu hợp lệ hoặc bật lại ràng buộc bằng cách sử dụng WITH NOCHECK
thay vào đó là đối số (điều này sẽ làm cho ràng buộc vẫn không đáng tin cậy).
Ví dụ 3 - Bật Ràng buộc bằng Cài đặt mặc định (CÓ KIỂM TRA)
Hãy bật lại ràng buộc và chạy lại truy vấn.
Để bật hạn chế, tôi sẽ lười và sử dụng cài đặt mặc định:
ALTER TABLE Occupation CHECK CONSTRAINT chkJobTitle;
Bây giờ hãy xác minh sự thay đổi:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Kết quả:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 1 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Bạn có thấy điều gì vừa xảy ra không? Mặc dù tôi đã bật lại ràng buộc, nhưng nó vẫn không đáng tin cậy.
Điều này là do tôi đã lười biếng (hoặc có thể chỉ là quên) khi tôi kích hoạt ràng buộc. Khi tôi bật ràng buộc, tôi đã quên chỉ định WITH CHECK
. Giá trị mặc định là WITH NOCHECK
có nghĩa là dữ liệu hiện có không được kiểm tra khi bật lại ràng buộc.
Đây là lý do tại sao bạn chắc chắn nên biết mình đang làm gì khi bật CHECK
(và FOREIGN KEY
) hạn chế. Do lười biếng và không chỉ định rõ ràng một cài đặt quan trọng có thể xảy ra, chúng tôi cho phép Máy chủ SQL làm ngơ trước bất kỳ vấn đề nào với dữ liệu hiện có.
Tuy nhiên, nếu toàn bộ lý do bạn cần để tắt ràng buộc là chèn dữ liệu vi phạm ràng buộc, thì WITH NOCHECK
mặc định có lẽ là những gì bạn muốn.
Nhân tiện, đối với các ràng buộc mới, mặc định là WITH CHECK
.
Nhưng trong trường hợp của tôi, tôi đã không chèn hoặc cập nhật bất kỳ dữ liệu sau khi vô hiệu hóa ràng buộc, vì vậy nếu trước đây nó đáng tin cậy thì bây giờ nó vẫn đáng tin cậy.
Vậy làm cách nào để tôi có thể tin cậy trở lại ràng buộc của mình?
Ví dụ 4 - Bật Ràng buộc bằng WITH CHECK
Nếu tôi muốn ràng buộc của mình được tin cậy trở lại, tôi cần chỉ định rõ ràng WITH CHECK
khi bật lại nó.
Hãy vô hiệu hóa lại ràng buộc:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Vì vậy, bây giờ tôi đã trở lại vị trí cũ trước khi bật lại.
Điều đáng lẽ tôi phải làm khi bật lại nó là:
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Bây giờ hãy xem xét ràng buộc khác:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Kết quả:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Phù! Ràng buộc của tôi một lần nữa đáng tin cậy.
Ví dụ 5 - Bật Ràng buộc KIỂM TRA với dữ liệu không hợp lệ
Tất nhiên, ràng buộc của tôi chỉ được tin cậy trở lại vì tôi đã không chèn dữ liệu không hợp lệ khi nó bị vô hiệu hóa. Nếu tôi đã làm điều này, tôi sẽ không thể bật nó bằng cách sử dụng WITH CHECK
, như được minh họa bên dưới.
Nếu tôi tắt lại:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Bây giờ hãy chèn dữ liệu không hợp lệ (và trả lại kết quả):
INSERT INTO Occupation VALUES ( 7, 'Digital Nomad' ); SELECT OccupationId, JobTitle FROM Occupation;
Kết quả:
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Digital Nomad | +----------------+-----------------+
Vậy là chúng tôi đã chèn thành công dữ liệu không hợp lệ (hàng cuối cùng).
Điều này không hợp lệ vì định nghĩa ràng buộc như sau:([JobTitle]<>'Digital Nomad')
Điều này có nghĩa là
JobTitle
cột không được chứa văn bản Digital Nomad
.
Bây giờ, hãy thử kích hoạt lại CHECK
ràng buộc bằng cách sử dụng WITH CHECK
và xem điều gì sẽ xảy ra.
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Kết quả:
Msg 547, Level 16, State 0, Line 1 The ALTER TABLE statement conflicted with the CHECK constraint "chkJobTitle". The conflict occurred in database "Test", table "dbo.Occupation", column 'JobTitle'.
Vì vậy, chúng tôi không thể kích hoạt lại ràng buộc bằng cách sử dụng WITH CHECK
trong khi chúng tôi có dữ liệu trong bảng vi phạm CHECK
hạn chế. Chúng tôi cần cập nhật dữ liệu hoặc chúng tôi cần sử dụng WITH NOCHECK
(hoặc đơn giản là bỏ qua hoàn toàn).
Hãy thử lại bằng cách sử dụng WITH NOCHECK
.
ALTER TABLE Occupation WITH NOCHECK CHECK CONSTRAINT chkJobTitle;
Kết quả:
Commands completed successfully. Total execution time: 00:00:00.015
Vì vậy, chúng tôi có thể bật thành công ràng buộc nếu chúng tôi không kiểm tra dữ liệu hiện có.
Tất nhiên, trong trường hợp này, CHECK
ràng buộc vẫn không được tin cậy. Nếu chúng tôi muốn ràng buộc được tin cậy, chúng tôi sẽ cần cập nhật dữ liệu để nó không vi phạm ràng buộc.
Ví dụ:
UPDATE Occupation SET JobTitle = 'Unemployed' WHERE OccupationId = 7; SELECT OccupationId, JobTitle FROM Occupation;
Kết quả:
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Unemployed | +----------------+-----------------+
Bây giờ chúng ta có thể thay đổi CHECK
ràng buộc để trở nên đáng tin cậy trở lại.
Hãy cùng làm cả ba:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle; ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle; SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Kết quả:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Vì vậy, giờ đây ràng buộc của chúng tôi đã được kích hoạt và đáng tin cậy một lần nữa, đồng thời cơ sở dữ liệu của chúng tôi không có người du mục kỹ thuật số!