2017-08-08 1 views
3

J'ai un exemple simple ci-dessouscontrainte de vérification ne fonctionne pas dans SQL Server 2016

begin tran 

CREATE TABLE [dbo].[Filters] 
(
    [Id]     INT NOT NULL IDENTITY, 
    [FCode]     varchar(30) null, 
    [FVersion]    varbinary(892) null, 

    CONSTRAINT [PK_Filter] PRIMARY KEY CLUSTERED ([Id]), 

    CONSTRAINT [CK_Filters_FCode_FVersion] 
     CHECK (([FCode] IS NULL AND [FVersion] IS NULL) 
       OR (LEN([FCode]) > 0 AND DATALENGTH([FVersion]) > 0)), 
) 

INSERT INTO [dbo].[Filters] (FCode, FVersion) 
VALUES (NULL, NULL), 
     (NULL, 0x6BE348), 
     ('ASD', NULL), 
     ('ASD', 0x6BE348) 

SELECT 
    IIF(([FCode] IS NULL AND [FVersion] IS NULL) 
     OR (LEN([FCode]) > 0 AND DATALENGTH([FVersion]) > 0) , 1, 0) AS [check], * 
FROM 
    [dbo].[filters] 

rollback 

Je pense que les 2e et 3e instructions d'insertion entraînera la violation de contrainte. Cependant le serveur les autorise.

Utilise l'instruction select pour voir que la valeur du contrôle de contrainte est violée pour les 2ème et 3ème lignes. Voir le résultat

check Id FCode FVersion 
------------------------------ 
1  1 NULL NULL 
0  2 NULL 0x6BE348 
0  3 ASD  NULL 
1  4 ASD  0x6BE348 

Toutes les idées?

Répondre

5

Les contraintes de vérification n'échouent que lorsque la valeur est définitivement false.

Les expressions que vous pensez enfreindre la contrainte évaluent UNKNOWN.

Vous pouvez voir cela avec

SELECT CASE 
     WHEN(([FCode] IS NULL 
       AND [FVersion] IS NULL) 
       OR (LEN([FCode]) > 0 
        AND DATALENGTH([FVersion]) > 0)) THEN 'True' 
     WHEN NOT (([FCode] IS NULL 
         AND [FVersion] IS NULL) 
        OR (LEN([FCode]) > 0 
          AND DATALENGTH([FVersion]) > 0)) THEN 'False' 
     ELSE 'Unknown' 
     END     AS [check], 
     LEN([FCode])   AS LenFCode, 
     DATALENGTH([FVersion]) AS DataLengthFVersion, 
     * 
FROM [dbo].[filters] 

qui retourne

+---------+----------+--------------------+----+-------+----------+ 
| check | LenFCode | DataLengthFVersion | Id | FCode | FVersion | 
+---------+----------+--------------------+----+-------+----------+ 
| True | NULL  | NULL    | 1 | NULL | NULL  | 
| Unknown | NULL  | 3     | 2 | NULL | 0x6BE348 | 
| Unknown | 3  | NULL    | 3 | ASD | NULL  | 
| True | 3  | 3     | 4 | ASD | 0x6BE348 | 
+---------+----------+--------------------+----+-------+----------+ 

La raison pour laquelle ils sont UNKNOWN est parce que LEN et DATALENGTH à la fois retour NULL lorsqu'il est passé NULL

+0

Merci! C'était la raison. –

+2

Excellent exemple – TheGameiswar

0

Martin Smith « s réponse déjà inclus la raison derrière laquelle le serveur SQL est autorisé des valeurs spécifiées sans violer la contrainte de vérification.

Vous pouvez modifier votre contrainte de vérification en la suivant pour la faire fonctionner. Demo

CONSTRAINT [CK_Filters_FCode_FVersion] 
     CHECK (([FCode] IS NULL AND [FVersion] IS NULL) 
       OR (LEN(ISNULL([FCode],'')) > 0 
        AND ISNULL(DATALENGTH([FVersion]),-1) > 0))