O que é um WITH CHECK CHECK CONSTRAINT?

18

Eu tenho algum T-SQL gerado automaticamente, o que provavelmente é válido, mas eu realmente não entendo.

ALTER TABLE [dbo].[MyTable]
WITH CHECK
CHECK CONSTRAINT [My_FORIEGN_KEY];

Eu sei o que é uma restrição de chave estrangeira, mas qual é o problema CHECK CHECK?

BanksySan
fonte

Respostas:

27

A página de documentação do MSDN sobre ALTER TABLEexplica estes:

  • ALTER TABLE: modifique a estrutura da tabela
    (e algumas das possíveis ações / modificações são):
    • CHECK CONSTRAINT ..: habilite a restrição
    • NOCHECK CONSTRAINT ..: desativar a restrição
      Também há etapas opcionais adicionais a serem executadas ao criar / ativar / desativar uma restrição:
      • WITH CHECK: verifique a restrição também
      • WITH NOCHECK: não verifique a restrição

Nas suas palavras:

| [ WITH { CHECK | NOCHECK } ] { CHECK | NOCHECK } CONSTRAINT   
    { ALL | constraint_name [ ,...n ] }

...

WITH CHECK | WITH NOCHECK Especifica se os dados na tabela é ou não validados contra um recém-adicionado ou re-habilitado FOREIGN KEYou CHECKrestrição . Se não especificado, WITH CHECKserá assumido para novas restrições e WITH NOCHECKassumido para restrições reativadas.

Se você não deseja verificar novas CHECKou FOREIGN KEYrestrições em relação aos dados existentes, use WITH NOCHECK. Não recomendamos fazer isso, exceto em casos raros. A nova restrição será avaliada em todas as atualizações de dados posteriores. Quaisquer violações de restrição suprimidas WITH NOCHECKquando a restrição é adicionada podem causar falhas em atualizações futuras se atualizarem linhas com dados que não estão em conformidade com a restrição.

O otimizador de consulta não considera restrições definidas WITH NOCHECK. Tais restrições são ignoradas até serem reativadas usando a ALTER TABLEtabela WITH CHECK CHECK CONSTRAINT ALL.

...

{ CHECK | NOCHECK } CONSTRAINT
Especifica que constraint_name está ativado ou desativado. Esta opção pode ser usada apenas com FOREIGN KEYe CHECKrestrições. Quando NOCHECKespecificada, a restrição é desativada e futuras inserções ou atualizações na coluna não são validadas com relação às condições da restrição. DEFAULT, PRIMARY KEY, E UNIQUErestrições não pode ser desativado.

Teste no dbfiddle :

CREATE TABLE a (aid INT PRIMARY KEY);

IR

INSERT INTO a (aid)
VALUES (1), (2), (3) ;

IR

3 linhas afetadas
CREATE TABLE b 
( aid INT,
  bid INT PRIMARY KEY,
  CONSTRAINT [My_FORIEGN_KEY]
    FOREIGN KEY (aid) REFERENCES a (aid)
) ;

IR

INSERT INTO b (aid, bid)
VALUES
  (1, 11),
  (1, 12),
  (2, 21), 
  (3, 31) ;

IR

4 linhas afetadas
INSERT INTO b (aid, bid)
VALUES
  (6, 61),
  (6, 62) ;

IR

Msg 547 Nível 16 Estado 0 Linha 1
A instrução INSERT entra em conflito com a restrição FOREIGN KEY "My_FORIEGN_KEY". O conflito ocorreu no banco de dados "fiddle_792fce5de09f42908c3a0f91421f3522", tabela "dbo.a", coluna 'aid'.
Msg 3621 Nível 0 Estado 0 Linha 1
A instrução foi encerrada.
SELECT * FROM b ;

IR

ajuda | licitação
-: | -:
  1 | 11
  1 | 12
  2 21
  3 31
ALTER TABLE b NOCHECK CONSTRAINT [My_FORIEGN_KEY];   --disable

IR

INSERT INTO b (aid, bid)
VALUES
  (4, 41),
  (4, 42) ;

IR

2 linhas afetadas
SELECT * FROM b ;

IR

ajuda | licitação
-: | -:
  1 | 11
  1 | 12
  2 21
  3 31
  4 41
  4 42.
ALTER TABLE b WITH NOCHECK CHECK CONSTRAINT [My_FORIEGN_KEY];  
-- enable constraint without checking existing data

IR

SELECT * FROM b ;

IR

ajuda | licitação
-: | -:
  1 | 11
  1 | 12
  2 21
  3 31
  4 41
  4 42.
INSERT INTO b (aid, bid)
VALUES
  (6, 61),
  (6, 62) ;

IR

Msg 547 Nível 16 Estado 0 Linha 1
A instrução INSERT entra em conflito com a restrição FOREIGN KEY "My_FORIEGN_KEY". O conflito ocorreu no banco de dados "fiddle_792fce5de09f42908c3a0f91421f3522", tabela "dbo.a", coluna 'aid'.
Msg 3621 Nível 0 Estado 0 Linha 1
A instrução foi encerrada.
SELECT * FROM b ;

IR

ajuda | licitação
-: | -:
  1 | 11
  1 | 12
  2 21
  3 31
  4 41
  4 42.
ALTER TABLE b WITH CHECK CHECK CONSTRAINT [My_FORIEGN_KEY];  
-- check existing data and enable constraint 

IR

Msg 547 Nível 16 Estado 0 Linha 1
A instrução ALTER TABLE entra em conflito com a restrição FOREIGN KEY "My_FORIEGN_KEY". O conflito ocorreu no banco de dados "fiddle_792fce5de09f42908c3a0f91421f3522", tabela "dbo.a", coluna 'aid'.
ypercubeᵀᴹ
fonte
11
Obrigado. Wrt ALTER TABLE b WITH NOCHECK CHECK CONSTRAINT [My_FORIEGN_KEY]; -- enable constraint without checking, isso significa que a restrição não verificará os dados existentes, apenas os novos dados recebidos?
BanksySan
11
Exatamente. Veja como a próxima inserção (aid = 6) não é permitida, mas as linhas existentes (com aid = 4) ainda estão lá.
ypercubeᵀᴹ
Isso demonstra perfeitamente.
BanksySan
1

Considere ler o artigo aqui: https://msdn.microsoft.com/en-us/library/ms190273.aspx

Ele nos diz: 'O otimizador de consulta não considera restrições definidas com WITH NOCHECK. Tais restrições são ignoradas até serem reativadas usando a tabela ALTER TABLE WITH CHECK CHECK CONSTRAINT ALL '

Além disso, considere este encadeamento no StackOverflow: /programming/529941/with-check-add-constraint-followed-by-check-constraint-vs-add-constraint

George K
fonte