Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Những điều bạn nên biết với NOCHECK khi kích hoạt ràng buộc CHECK trong SQL Server

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 NOCHECKWITH 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 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ố!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để trả về số ngẫu nhiên dưới dạng một cột trong SQL Server 2005?

  2. Xây dựng mô hình học máy với SQL Server, ML.NET và C #

  3. Ràng buộc cơ sở dữ liệu là gì?

  4. Nhận quyền thực thi đối với xp_cmdshell

  5. datetime so với smalldatetime trong SQL Server:Sự khác biệt là gì?