Se você se encontrar na situação em que precisa reativar um
CHECK
restrição que foi anteriormente desabilitada, você definitivamente deve se certificar de que sabe o que está fazendo. Em particular, você deve entender a diferença entre
WITH NOCHECK
e WITH CHECK
argumentos. Esses argumentos podem ser usados no momento em que você habilita a restrição. Eles especificam se os dados existentes são validados ou não em relação ao seu
CHECK
reativado (ou adicionado recentemente) limitação. Basicamente, você tem a opção de verificar todos os dados existentes para quaisquer violações contra a restrição. Se você não especificar nada, os dados existentes não ser verificado. Por isso é importante entender como funciona. A propósito, esses argumentos também se aplicam a restrições de chave estrangeira.
Como você pode esperar,
WITH CHECK
especifica que os dados existentes são validados e WITH NOCHECK
especifica que não. O padrão é WITH NOCHECK
. Se você usar
WITH NOCHECK
, a restrição será sinalizada como não confiável. Na verdade, ele é sinalizado como não confiável quando você desativa a restrição. Mas quando você reativá-lo, ele permanecerá não confiável, a menos que você use WITH CHECK
. Em outras palavras, se você deseja reafirmar sua “confiabilidade”, você deve especificar isso explicitamente. Em outras palavras:
- Quando você usa
WITH NOCHECK
, a restrição permanecerá não confiável. - Quando você usa
WITH CHECK
ele se tornará confiável, mas somente se todos os dados existentes estiverem em conformidade com a restrição. Se algum dado existente violar a restrição, a restrição não será habilitada e você receberá uma mensagem de erro.
Claro, quando digo “todos os dados existentes” estou me referindo apenas aos dados aos quais a restrição se aplica.
Pode haver cenários em que você desativou intencionalmente uma restrição porque teve que inserir dados que violam a restrição. Nesses casos, se os dados inválidos devem permanecer no banco de dados, você precisará usar
WITH NOCHECK
se você quiser reativar a restrição. Isso permitirá que você habilite a restrição sem que nenhum dado existente atrapalhe. Abaixo estão exemplos que demonstram isso.
Exemplo 1 – Revisar restrições de VERIFICAÇÃO
Primeiro, vamos usar as
sys.check_constraints
para dar uma olhada em todos os CHECK
restrições no banco de dados atual. SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Resultado:
+-----------------+---------------+------------------+----------------------------------------+ | 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') | +-----------------+---------------+------------------+----------------------------------------+
Podemos ver que todos estão habilitados e confiáveis (porque todos têm zeros no is_disabled e is_not_trusted colunas).
Para este artigo, vou desativar e reativar o chkJobTitle limitação.
Exemplo 2 – Desativar a restrição
Aqui, desabilito o chkJobTitle limitação:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Feito.
Agora vamos revisar todas as restrições novamente:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Resultado:
+-----------------+---------------+------------------+----------------------------------------+ | 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') | +-----------------+---------------+------------------+----------------------------------------+
Podemos ver que ele foi desativado (porque seu is_disabled coluna está definida como 1 ).
Você pode notar que o is_not_trusted coluna também está definida como 1 . Isso indica que o
CHECK
restrição não foi verificada pelo sistema para todas as linhas. Como mencionado, um
CHECK
A restrição só pode ser confiável se todos os dados tiverem passado com sucesso nas condições da restrição. Quando desabilitamos uma restrição, isso abre a possibilidade de dados inválidos entrarem no banco de dados. Portanto, não podemos ter 100% de certeza de que todos os dados são válidos, portanto, a restrição está sendo sinalizada como não confiável. A maneira de garantir que a restrição seja confiável novamente é reativá-la usando o
WITH CHECK
argumento. Isso fará com que a restrição verifique todos os dados antes de ser reativada. Se algum dado for inválido, ele não poderá ser reativado. Você precisará atualizar os dados para que sejam válidos ou reativar a restrição usando o WITH NOCHECK
argumento (o que fará com que a restrição permaneça não confiável). Exemplo 3 – Habilite a restrição usando as configurações padrão (COM NOCHECK)
Vamos reativar a restrição e executar a consulta novamente.
Para habilitar a restrição, serei preguiçoso e usarei as configurações padrão:
ALTER TABLE Occupation CHECK CONSTRAINT chkJobTitle;
Agora verifique a alteração:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Resultado:
+-----------------+---------------+------------------+----------------------------------------+ | 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') | +-----------------+---------------+------------------+----------------------------------------+
Você viu o que acabou de acontecer? Mesmo que eu tenha habilitado a restrição novamente, ela ainda não é confiável.
Isso ocorre porque eu era preguiçoso (ou talvez apenas esquecido) quando habilitei a restrição. Quando habilitei a restrição, esqueci de especificar
WITH CHECK
. O padrão é WITH NOCHECK
o que significa que os dados existentes não são verificados ao reativar a restrição. É por isso que você definitivamente deve saber o que está fazendo ao ativar
CHECK
(e FOREIGN KEY
) restrições. Por ser preguiçoso e não especificar explicitamente uma configuração potencialmente importante, damos permissão ao SQL Server para fechar os olhos a quaisquer problemas com dados existentes. No entanto, se todo o motivo pelo qual você precisava desabilitar a restrição é inserir dados que violam a restrição, então o padrão
WITH NOCHECK
é provavelmente o que você quer. A propósito, para novas restrições, o padrão é
WITH CHECK
. Mas, no meu caso, não inseri ou atualizei nenhum dados após desabilitar a restrição, portanto, se era confiável antes, ainda deve ser confiável agora.
Então, como posso obter minha restrição confiável novamente?
Exemplo 4 – Habilite a restrição usando WITH CHECK
Se eu quiser que minha restrição seja confiável novamente, preciso especificar explicitamente
WITH CHECK
ao reativá-lo. Vamos desabilitar a restrição novamente:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Então agora estou de volta para onde estava antes de reativar.
O que eu deveria ter feito quando reativei foi isso:
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Agora dê outra olhada na restrição:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Resultado:
+-----------------+---------------+------------------+----------------------------------------+ | 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') | +-----------------+---------------+------------------+----------------------------------------+
Ufa! Minha restrição é confiável mais uma vez.
Exemplo 5 – Habilitar a restrição CHECK com dados inválidos
Claro, minha restrição só é confiável novamente porque não inseri dados inválidos enquanto ela estava desabilitada. Se eu tivesse feito isso, não seria capaz de habilitá-lo usando
WITH CHECK
, conforme demonstrado abaixo. Se eu desabilitar novamente:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Agora insira dados inválidos (e retorne os resultados):
INSERT INTO Occupation VALUES ( 7, 'Digital Nomad' ); SELECT OccupationId, JobTitle FROM Occupation;
Resultado:
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Digital Nomad | +----------------+-----------------+
Então, inserimos com sucesso dados inválidos (última linha).
Isso é inválido porque a definição de restrição é a seguinte:
([JobTitle]<>'Digital Nomad')
Isso significa que o JobTitle a coluna não deve conter o texto
Digital Nomad
. Agora vamos tentar reativar o
CHECK
restrição usando WITH CHECK
e veja o que acontece. ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Resultado:
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'.
Portanto, não podemos reativar a restrição usando
WITH CHECK
enquanto temos dados na tabela que violam o CHECK
limitação. Ou precisamos atualizar os dados ou precisamos usar WITH NOCHECK
(ou simplesmente omiti-lo completamente). Vamos tentar novamente usando
WITH NOCHECK
. ALTER TABLE Occupation WITH NOCHECK CHECK CONSTRAINT chkJobTitle;
Resultado:
Commands completed successfully. Total execution time: 00:00:00.015
Assim, podemos habilitar com sucesso a restrição se não verificarmos os dados existentes.
Claro, neste caso o
CHECK
restrição ainda não é confiável. Se quisermos que a restrição seja confiável, precisaremos atualizar os dados para que não viole a restrição. Exemplo:
UPDATE Occupation SET JobTitle = 'Unemployed' WHERE OccupationId = 7; SELECT OccupationId, JobTitle FROM Occupation;
Resultado:
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Unemployed | +----------------+-----------------+
Agora podemos alterar o
CHECK
restrição para se tornar confiável novamente. Vamos fazer os três juntos:
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;
Resultado:
+-----------------+---------------+------------------+----------------------------------------+ | 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') | +-----------------+---------------+------------------+----------------------------------------+
Então agora nossa restrição está habilitada e confiável mais uma vez, e nosso banco de dados está livre de nômades digitais!