Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Co powinieneś wiedzieć o funkcji NOCHECK podczas włączania ograniczenia CHECK w SQL Server

Jeśli kiedykolwiek znajdziesz się w sytuacji, w której będziesz musiał ponownie włączyć CHECK ograniczenie, które zostało wcześniej wyłączone, zdecydowanie powinieneś upewnić się, że wiesz, co robisz.

W szczególności powinieneś zrozumieć różnicę między WITH NOCHECK i WITH CHECK argumenty.

Te argumenty mogą być używane podczas włączania ograniczenia. Określają, czy istniejące dane są sprawdzane pod kątem ponownie włączonych (lub nowo dodanych) CHECK ograniczenie. Zasadniczo masz możliwość sprawdzenia wszystkich istniejących danych pod kątem jakichkolwiek naruszeń ograniczenia. Jeśli nic nie określisz, istniejące dane nie będą być sprawdzone. Dlatego ważne jest, aby zrozumieć, jak to działa.

Nawiasem mówiąc, te argumenty odnoszą się również do ograniczeń kluczy obcych.

Jak można się spodziewać, WITH CHECK określa, że ​​istniejące dane są sprawdzane i WITH NOCHECK określa, że ​​tak nie jest. Wartość domyślna to WITH NOCHECK .

Jeśli używasz WITH NOCHECK , ograniczenie zostanie oznaczone jako niezaufane. W rzeczywistości jest oznaczany jako niezaufany po wyłączeniu ograniczenia. Ale po ponownym włączeniu pozostanie niezaufane, chyba że użyjesz WITH CHECK . Innymi słowy, jeśli chcesz ponownie określić jego „wiarygodność”, musisz to wyraźnie określić.

Innymi słowy:

  • Gdy używasz WITH NOCHECK , ograniczenie pozostanie niezaufane.
  • Gdy używasz WITH CHECK stanie się zaufany, ale tylko wtedy, gdy wszystkie istniejące dane będą zgodne z ograniczeniem. Jeśli jakiekolwiek istniejące dane naruszają ograniczenie, ograniczenie nie zostanie włączone i otrzymasz komunikat o błędzie.

Oczywiście, kiedy mówię „wszystkie istniejące dane”, mam na myśli tylko dane, których dotyczy ograniczenie.

Mogą istnieć scenariusze, w których celowo wyłączyłeś ograniczenie, ponieważ musiałeś wprowadzić dane, które naruszają ograniczenie. W takich przypadkach, jeśli nieprawidłowe dane muszą pozostać w bazie danych, musisz użyć WITH NOCHECK jeśli chcesz ponownie włączyć ograniczenie. Umożliwi to włączenie ograniczenia bez przeszkadzania istniejącym danym.

Poniżej znajdują się przykłady, które to pokazują.

Przykład 1 – Przegląd Sprawdź ograniczenia

Najpierw użyjmy sys.check_constraints aby rzucić okiem na wszystkie CHECK ograniczenia w bieżącej bazie danych.

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

Wynik:

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

Widzimy, że wszystkie są włączone i zaufane (ponieważ wszystkie mają zera w is_disabled i jest_nie_zaufany kolumny).

W tym artykule wyłączę i ponownie włączę chkJobTitle ograniczenie.

Przykład 2 – Wyłącz ograniczenie

Tutaj wyłączam chkJobTitle ograniczenie:

ALTER TABLE Occupation  
NOCHECK CONSTRAINT chkJobTitle; 

Gotowe.

Teraz ponownie przejrzyjmy wszystkie ograniczenia:

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

Wynik:

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

Widzimy, że został wyłączony (ponieważ jego jest_wyłączony kolumna jest ustawiona na 1 ).

Możesz zauważyć, że jest_nie_zaufany kolumna jest również ustawiona na 1 . Oznacza to, że CHECK ograniczenie nie zostało zweryfikowane przez system dla wszystkich wierszy.

Jak wspomniano, CHECK Ograniczeniu można zaufać tylko wtedy, gdy wszystkie dane pomyślnie spełniły warunki ograniczenia. Gdy wyłączymy ograniczenie, otwiera to możliwość wprowadzenia nieprawidłowych danych do bazy danych. Dlatego nie możemy być w 100% pewni, że wszystkie dane są prawidłowe, dlatego ograniczenie jest oznaczane jako niezaufane.

Sposobem na upewnienie się, że ograniczenie jest ponownie zaufane, jest ponowne włączenie go za pomocą WITH CHECK argument. Spowoduje to, że ograniczenie sprawdzi wszystkie dane przed ponownym włączeniem. Jeśli jakiekolwiek dane są nieprawidłowe, nie będzie można ich ponownie włączyć. Musisz albo zaktualizować dane, aby były prawidłowe, albo ponownie włączyć ograniczenie za pomocą WITH NOCHECK zamiast tego argument (co spowoduje, że ograniczenie pozostanie niezaufane).

Przykład 3 – Włącz ograniczenie przy użyciu ustawień domyślnych (BEZ SPRAWDZANIA)

Włączmy ponownie ograniczenie i ponownie uruchom zapytanie.

Aby włączyć ograniczenie, będę leniwy i użyję ustawień domyślnych:

ALTER TABLE Occupation  
CHECK CONSTRAINT chkJobTitle; 

Teraz zweryfikuj zmianę:

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

Wynik:

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

Widziałeś, co się właśnie stało? Mimo że ponownie włączyłem ograniczenie, nadal nie jest ono zaufane.

To dlatego, że byłem leniwy (a może po prostu zapominalski), kiedy włączyłem ograniczenie. Kiedy włączyłem ograniczenie, zapomniałem określić WITH CHECK . Wartość domyślna to WITH NOCHECK co oznacza, że ​​istniejące dane nie są sprawdzane podczas ponownego włączania ograniczenia.

Dlatego zdecydowanie powinieneś wiedzieć, co robisz, włączając CHECK (i FOREIGN KEY ) ograniczenia. Będąc leniwym i nie określając wprost potencjalnie ważnego ustawienia, dajemy SQL Serverowi pozwolenie na przymykanie oczu na wszelkie problemy z istniejącymi danymi.

Jeśli jednak jedynym powodem, dla którego musiałeś wyłączyć ograniczenie, jest wstawienie danych, które naruszają ograniczenie, wówczas domyślny WITH NOCHECK jest prawdopodobnie tym, czego chcesz.

Nawiasem mówiąc, dla nowych ograniczeń domyślnym ustawieniem jest WITH CHECK .

Ale w moim przypadku nie wstawiłem ani nie zaktualizowałem żadnego dane po wyłączeniu ograniczenia, więc jeśli wcześniej były godne zaufania, powinny być teraz godne zaufania.

Jak więc mogę ponownie zaufać mojemu ograniczeniu?

Przykład 4 – Włącz ograniczenie za pomocą WITH CHECK

Jeśli chcę, aby moje ograniczenie było ponownie zaufane, muszę wyraźnie określić WITH CHECK po ponownym włączeniu.

Wyłączmy ponownie ograniczenie:

ALTER TABLE Occupation  
NOCHECK CONSTRAINT chkJobTitle; 

Więc teraz wróciłem do miejsca, w którym byłem przed ponownym włączeniem.

To, co powinienem zrobić po ponownym włączeniu, to:

ALTER TABLE Occupation  
WITH CHECK CHECK CONSTRAINT chkJobTitle; 

Teraz spójrz ponownie na ograniczenie:

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

Wynik:

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

Uff! Moje ograniczenie jest ponownie godne zaufania.

Przykład 5 – Włącz ograniczenie SPRAWDŹ z nieprawidłowymi danymi

Oczywiście moje ograniczenie jest ponownie zaufane tylko dlatego, że nie wstawiłem nieprawidłowych danych, gdy było wyłączone. Gdybym to zrobił, nie byłbym w stanie go włączyć za pomocą WITH CHECK , jak pokazano poniżej.

Jeśli ponownie go wyłączę:

ALTER TABLE Occupation  
NOCHECK CONSTRAINT chkJobTitle; 

Teraz wstaw nieprawidłowe dane (i zwróć wyniki):

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

SELECT 
  OccupationId,
  JobTitle
FROM Occupation;

Wynik:

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

Więc pomyślnie wstawiliśmy nieprawidłowe dane (ostatni wiersz).

Jest to nieprawidłowe, ponieważ definicja ograniczenia wygląda następująco:([JobTitle]<>'Digital Nomad')

Oznacza to, że JobTitle kolumna nie może zawierać tekstu Digital Nomad .

Teraz spróbujmy ponownie włączyć CHECK ograniczenie przy użyciu WITH CHECK i zobacz, co się stanie.

ALTER TABLE Occupation  
WITH CHECK CHECK CONSTRAINT chkJobTitle; 

Wynik:

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

Dlatego nie możemy ponownie włączyć ograniczenia za pomocą WITH CHECK podczas gdy mamy w tabeli dane, które naruszają CHECK ograniczenie. Albo musimy zaktualizować dane, albo użyć WITH NOCHECK (lub po prostu pomiń go całkowicie).

Spróbujmy jeszcze raz, używając WITH NOCHECK .

ALTER TABLE Occupation  
WITH NOCHECK CHECK CONSTRAINT chkJobTitle; 

Wynik:

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

Możemy więc z powodzeniem włączyć ograniczenie, jeśli nie sprawdzimy istniejących danych.

Oczywiście w tym przypadku CHECK ograniczenie nadal nie jest zaufane. Jeśli chcemy, aby ograniczenie było zaufane, musimy zaktualizować dane, aby nie naruszały ograniczenia.

Przykład:

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

SELECT 
  OccupationId,
  JobTitle
FROM Occupation;

Wynik:

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

Teraz możemy zmienić CHECK ograniczenie, aby ponownie stać się zaufanym.

Zróbmy wszystkie trzy razem:

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;

Wynik:

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

Więc teraz nasze ograniczenie jest ponownie włączone i godne zaufania, a nasza baza danych jest wolna od cyfrowych nomadów!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Używanie StringWriter do serializacji XML

  2. SQL Server — co się dzieje po zaktualizowaniu wiersza w tabeli?

  3. Przeprowadź analizę produktu za pomocą wyszukiwania pełnotekstowego programu SQL Server. Część 1

  4. SQL Server:maksymalna liczba wierszy w tabeli

  5. Błąd SQL z zamówieniem według w podzapytaniu