Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Какво трябва да знаете за С NOCHECK, когато активирате ограничение CHECK в SQL Server

Ако някога се окажете в ситуация, в която трябва да активирате отново CHECK ограничение, което преди е било деактивирано, определено трябва да се уверите, че знаете какво правите.

По-специално, трябва да разберете разликата между WITH NOCHECK и WITH CHECK аргументи.

Тези аргументи могат да се използват в момента, в който активирате ограничението. Те уточняват дали съществуващите данни се потвърждават или не спрямо повторно активираните (или новодобавени) CHECK ограничение. По принцип имате възможност да проверите всички съществуващи данни за нарушения на ограничението. Ако не посочите нищо, съществуващите данни няма бъде проверен. Ето защо е важно да разберете как работи.

Между другото, тези аргументи се отнасят и за ограниченията на външния ключ.

Както може да очаквате, WITH CHECK указва, че съществуващите данни са валидирани и WITH NOCHECK уточнява, че не е така. По подразбиране е WITH NOCHECK .

Ако използвате WITH NOCHECK , ограничението ще бъде маркирано като ненадеждно. Всъщност той е маркиран като ненадежден, когато деактивирате ограничението. Но когато го активирате отново, той ще остане ненадежден, освен ако не използвате WITH CHECK . С други думи, ако искате да повторите неговата „надеждност“, трябва изрично да посочите това.

С други думи:

  • Когато използвате WITH NOCHECK , ограничението ще остане ненадеждно.
  • Когато използвате WITH CHECK ще стане доверен, но само ако всички съществуващи данни отговарят на ограничението. Ако някакви съществуващи данни нарушават ограничението, ограничението няма да бъде активирано и ще получите съобщение за грешка.

Разбира се, когато казвам „всички съществуващи данни“, имам предвид само данни, за които се прилага ограничението.

Възможно е да има сценарии, при които умишлено сте деактивирали ограничение, защото е трябвало да въведете данни, които нарушават ограничението. В такива случаи, ако невалидните данни трябва да останат в базата данни, ще трябва да използвате WITH NOCHECK ако искате да активирате отново ограничението. Това ще ви позволи да активирате ограничението, без никакви съществуващи данни да пречат.

По-долу са дадени примери, които демонстрират това.

Пример 1 – Преглед на ограниченията CHECK

Първо, нека използваме sys.check_constraints за да разгледате всички CHECK ограничения в текущата база данни.

SELECT 
  name,
  is_disabled,
  is_not_trusted,
  definition
FROM sys.check_constraints;

Резултат:

+-----------------+---------------+------------------+----------------------------------------+
| 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')          |
+-----------------+---------------+------------------+----------------------------------------+

Можем да видим, че всички те са активирани и надеждни (защото всички имат нули в is_disabled и не_доверен колони).

За тази статия ще деактивирам и активирам отново chkJobTitle ограничение.

Пример 2 – Деактивиране на ограничението

Тук деактивирам chkJobTitle ограничение:

ALTER TABLE Occupation  
NOCHECK CONSTRAINT chkJobTitle; 

Готово.

Сега нека прегледаме отново всички ограничения:

SELECT 
  name,
  is_disabled,
  is_not_trusted,
  definition
FROM sys.check_constraints;

Резултат:

+-----------------+---------------+------------------+----------------------------------------+
| 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')          |
+-----------------+---------------+------------------+----------------------------------------+

Можем да видим, че е деактивиран (защото is_disabled колоната е настроена на 1 ).

Може да забележите, че is_not_trusted колоната също е настроена на 1 . Това показва, че CHECK ограничението не е проверено от системата за всички редове.

Както споменахме, CHECK на ограничението може да се има доверие само ако всички данни са преминали успешно условията на ограничението. Когато деактивираме ограничение, това отваря потенциала невалидни данни да влязат в базата данни. Следователно не можем да бъдем 100% сигурни, че всички данни са валидни, поради което ограничението е маркирано като ненадеждно.

Начинът да гарантирате, че ограничението отново е надеждно, е да го активирате отново с помощта на WITH CHECK аргумент. Това ще накара ограничението да провери всички данни, преди да бъде повторно активирано. Ако някои данни са невалидни, те няма да могат да бъдат активирани отново. Ще трябва или да актуализирате данните, така че да са валидни, или да активирате отново ограничението с помощта на WITH NOCHECK вместо аргумент (което ще накара ограничението да остане ненадеждно).

Пример 3 – Активирайте ограничението, като използвате настройките по подразбиране (С NOCHECK)

Нека да активираме отново ограничението и да стартираме заявката отново.

За да активирам ограничението, ще бъда мързелив и ще използвам настройките по подразбиране:

ALTER TABLE Occupation  
CHECK CONSTRAINT chkJobTitle; 

Сега проверете промяната:

SELECT 
  name,
  is_disabled,
  is_not_trusted,
  definition
FROM sys.check_constraints;

Резултат:

+-----------------+---------------+------------------+----------------------------------------+
| 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')          |
+-----------------+---------------+------------------+----------------------------------------+

Видяхте ли какво се случи току-що? Въпреки че отново активирах ограничението, то все още не е надеждно.

Това е така, защото бях мързелив (или може би просто забравих), когато активирах ограничението. Когато активирах ограничението, забравих да посоча WITH CHECK . По подразбиране е WITH NOCHECK което означава, че съществуващите данни не се проверяват при повторното активиране на ограничението.

Ето защо определено трябва да знаете какво правите, когато активирате CHECKFOREIGN KEY ) ограничения. Като сме мързеливи и не указваме изрично потенциално важна настройка, ние даваме разрешение на SQL Server да си затваря очите за всякакви проблеми със съществуващите данни.

Въпреки това, ако цялата причина, поради която трябва да деактивирате ограничението, е да вмъкнете данни, които нарушават ограничението, тогава WITH NOCHECK по подразбиране вероятно е това, което искате.

Между другото, за новите ограничения по подразбиране е WITH CHECK .

Но в моя случай не вмъкнах или актуализирах никоя данни след деактивиране на ограничението, така че ако преди е било надеждно, сега трябва да е надеждно.

И така, как мога да получа отново доверие на моето ограничение?

Пример 4 – Активирайте ограничението с помощта на WITH CHECK

Ако искам отново да има доверие на моето ограничение, трябва изрично да посоча WITH CHECK когато го активирате отново.

Нека отново деактивираме ограничението:

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;

Резултат:

+-----------------+---------------+------------------+----------------------------------------+
| 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')          |
+-----------------+---------------+------------------+----------------------------------------+

фу! Моето ограничение отново е надеждно.

Пример 5 – Активиране на ограничението CHECK с невалидни данни

Разбира се, моето ограничение отново се доверява само, защото не вмъкнах невалидни данни, докато беше деактивирано. Ако бях направил това, нямаше да мога да го активирам с помощта на WITH CHECK , както е показано по-долу.

Ако го деактивирам отново:

ALTER TABLE Occupation  
NOCHECK CONSTRAINT chkJobTitle; 

Сега поставете невалидни данни (и върнете резултатите):

INSERT INTO Occupation
VALUES ( 7, 'Digital Nomad' );

SELECT 
  OccupationId,
  JobTitle
FROM Occupation;

Резултат:

+----------------+-----------------+
| OccupationId   | JobTitle        |
|----------------+-----------------|
| 1              | Engineer        |
| 2              | Accountant      |
| 3              | Cleaner         |
| 4              | Attorney        |
| 5              | Sales Executive |
| 6              | Uber Driver     |
| 7              | Digital Nomad   |
+----------------+-----------------+

Така че успешно вмъкнахме невалидни данни (последен ред).

Това е невалидно, тъй като дефиницията на ограничението е както следва:([JobTitle]<>'Digital Nomad')

Това означава, че JobTitle колоната не трябва да съдържа текста Digital Nomad .

Сега нека се опитаме да активираме отново CHECK ограничение с помощта на WITH CHECK и вижте какво ще се случи.

ALTER TABLE Occupation  
WITH CHECK CHECK CONSTRAINT chkJobTitle; 

Резултат:

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'.

Така че не можем да активираме отново ограничението с помощта на WITH CHECK докато имаме данни в таблицата, които нарушават CHECK ограничение. Или трябва да актуализираме данните, или трябва да използваме WITH NOCHECK (или просто го пропуснете напълно).

Нека опитаме отново с WITH NOCHECK .

ALTER TABLE Occupation  
WITH NOCHECK CHECK CONSTRAINT chkJobTitle; 

Резултат:

Commands completed successfully.
Total execution time: 00:00:00.015

Така че можем успешно да активираме ограничението, ако не проверим съществуващите данни.

Разбира се, в този случай CHECK на ограничението все още не се вярва. Ако искаме ограничението да бъде надеждно, ще трябва да актуализираме данните, така че да не нарушават ограничението.

Пример:

UPDATE Occupation
SET JobTitle = 'Unemployed'
WHERE OccupationId = 7;

SELECT 
  OccupationId,
  JobTitle
FROM Occupation;

Резултат:

+----------------+-----------------+
| OccupationId   | JobTitle        |
|----------------+-----------------|
| 1              | Engineer        |
| 2              | Accountant      |
| 3              | Cleaner         |
| 4              | Attorney        |
| 5              | Sales Executive |
| 6              | Uber Driver     |
| 7              | Unemployed      |
+----------------+-----------------+

Сега можем да променим CHECK ограничение да станете отново доверени.

Нека направим и трите заедно:

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;

Резултат:

+-----------------+---------------+------------------+----------------------------------------+
| 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')          |
+-----------------+---------------+------------------+----------------------------------------+

Така че сега нашето ограничение отново е активирано и надеждно, а нашата база данни е свободна от цифрови номади!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Използване на SQL Server като DB опашка с множество клиенти

  2. SQL Server:Направете всички главни букви в правилен регистър/заглавие

  3. Запитване на SQL сървър за получаване на списъка с колони в таблица заедно с ограниченията типове данни, NOT NULL и PRIMARY KEY

  4. Избягвайте дублирането в заявката INSERT INTO SELECT в SQL Server

  5. Как да премахнете колона в SQL Server с помощта на T-SQL