SQL Server na prática

Escrever CHECK que representem a regra de negócio

Trate NULL explicitamente, defina estados válidos por linha e entenda os limites de CHECK antes de usá-lo como garantia de integridade.

Uma constraint chamada PositiveQuantity parece garantir quantidade positiva em toda linha. Se a expressão for Quantity > 0 e a coluna permitir NULL, essa promessa está incompleta. O SQL Server rejeita FALSE, enquanto UNKNOWN causado por NULL pode passar. O nome não adiciona uma regra de execução.

Descrever os estados permitidos

A primeira tabela demonstra a diferença: inserir NULL funciona. Se a quantidade é obrigatória, combine NOT NULL com a verificação positiva. Se desconhecido é um estado válido, documente esse significado em vez de afirmar que CHECK exige um número.

A segunda tabela representa publicação. Um rascunho não pode ter data de publicação; uma linha publicada precisa dela. Status é obrigatório e limitado aos dois valores previstos.

CREATE TABLE #WeakRule
(
    ItemId int PRIMARY KEY,
    Quantity int NULL CHECK (Quantity > 0)
);
INSERT #WeakRule VALUES (1, NULL);
SELECT ItemId, Quantity FROM #WeakRule;

CREATE TABLE #PublicationRule
(
    ItemId int PRIMARY KEY,
    Status varchar(10) NOT NULL
        CHECK (Status IN ('Draft', 'Published')),
    PublishedAt datetime2(0) NULL,
    CHECK
    (
        (Status = 'Draft' AND PublishedAt IS NULL)
        OR
        (Status = 'Published' AND PublishedAt IS NOT NULL)
    )
);
INSERT #PublicationRule VALUES
(1, 'Draft', NULL),
(2, 'Published', '20250115T12:00:00');

BEGIN TRY
    INSERT #PublicationRule VALUES (3, 'Published', NULL);
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER() AS ConstraintError;
END CATCH;
SELECT * FROM #PublicationRule ORDER BY ItemId;
DROP TABLE #PublicationRule;
DROP TABLE #WeakRule;

A regra fraca retorna sua linha NULL. A tabela de publicação aceita as duas primeiras e rejeita a terceira. IS NULL e IS NOT NULL explícitos evitam UNKNOWN acidental na relação entre colunas.

Antes de implementar uma condição composta, escreva uma pequena tabela verdade. Inclua Draft com e sem data, Published com e sem data, status desconhecido e status NULL. Transforme esses casos em verificações de migração ou integração. Testar somente inserts válidos deixa a parte principal sem avaliação.

Mantenha as expressões compreensíveis. Uma cadeia longa de negações pode estar correta e ser difícil de ampliar. Separe regras independentes de domínio das relações entre colunas. Nomes claros em constraints persistentes ajudam a identificar a causa de um erro.

Entender o limite da linha

CHECK serve para invariantes da própria linha, como intervalo permitido ou data final posterior à inicial. Ele não é um agendador que reavalia registros conforme o tempo passa. Uma expressão com o relógio atual é verificada nas gravações relevantes, não continuamente à meia-noite.

Também não esconda regras globais de estoque ou quantidade mínima de registros em uma função escalar chamada por CHECK. Outras linhas podem mudar sem reavaliar a original, e exclusões trazem lacunas adicionais. Use constraints relacionais adequadas ou uma transação que proteja o invariante compartilhado.

Uma chave estrangeira expressa associação com outra tabela melhor que uma função de busca. Uma regra UNIQUE protege unicidade melhor que contar duplicatas aparentes. 'Somente uma atribuição atual' pode exigir índice único filtrado, não apenas datas válidas em cada registro.

Autorização continua sendo outra responsabilidade. Uma linha estruturalmente válida pode pertencer a um tenant que o chamador não pode alterar. O contrato de gravação precisa verificar ambos os aspectos.

Implantar sem ocultar violações existentes

Adicionar uma constraint validada exige que as linhas existentes a satisfaçam. Procure violações e decida correção ou quarentena. Preencher ausências com valores inventados apenas para concluir a migração altera os dados do negócio.

Uma constraint pode estar habilitada e não confiável quando dados antigos não foram validados. Consulte is_disabled e is_not_trusted em sys.check_constraints. Para uma constraint existente, WITH CHECK CHECK CONSTRAINT permite verificar as linhas e estabelecer confiança. Planeje o trabalho e os locks em uma tabela grande.

Teste também updates. A mudança de Draft para Published precisa definir PublishedAt na mesma instrução. Alterar primeiro o status e depois a data cria um estado intermediário inválido. A falha exige que a aplicação expresse uma transição coerente.

Por fim, defina mensagens compreensíveis para erros de constraint. A validação antecipada na aplicação ajuda o usuário, mas o banco permanece a defesa final. Ao acrescentar um estado como Archived, altere modelo, migração e testes de transição em conjunto. Enfraquecer a expressão até o novo código passar não preserva necessariamente a regra desejada.

Referências técnicas: Microsoft Learn: CHECK constraints · Microsoft Learn: sys.check_constraints.

Pergunte sobre este artigo

Tem alguma dúvida sobre este tema?

Conte o que você está avaliando ou onde encontrou dificuldades. Responderemos com uma recomendação prática.

Inquiries are not enabled in this preview.

Fazer uma pergunta sobre este artigo