2017-08-08 138 views
3

工作,我有以下檢查約束不會在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 

我想到的是,第二和第三插入語句會導致違反約束一個簡單的例子。但是服務器允許它們。

使用select語句查看第2行和第3行違反約束檢查的值。查看結果

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

任何想法?

回答

5

檢查約束條件只有當值爲最終值時纔會失敗false

您希望違反約束條件的表達式評估爲UNKNOWN

您可以

​​

它返回

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

之所以看到這一點,他們是UNKNOWN是因爲LENDATALENGTH都在傳遞NULL

+0

謝謝!這是原因。 –

+2

極好的例子 – TheGameiswar

0

Martin Smith的答案已經返回NULL包括爲什麼SQL服務器被允許的原因在不違反檢查約束的情況下指定值。

您可以修改您的檢查約束以使其工作。 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))