这是MERGE中的错误,无法正确实施FOREIGN KEY吗?

A-K*_*A-K 14 sql-server sql-server-2008 sql-server-2008-r2

我使用下面的表来实现子类型,这是一种非常常见的方法:

CREATE TABLE dbo.Vehicles(
    ID INT NOT NULL, 
    [Type] VARCHAR(5) NOT NULL,
    CONSTRAINT Vehicles_PK PRIMARY KEY(ID),
    CONSTRAINT Vehicles_UNQ_ID_Type UNIQUE(ID, [Type]),
    CONSTRAINT Vehicles_CHK_ValidTypes CHECK([Type] IN ('Car', 'Truck'))
);
GO

CREATE TABLE dbo.Cars(ID INT NOT NULL,
    [Type] AS CAST('Car' AS VARCHAR(5)) PERSISTED,
    OtherData VARCHAR(10) NULL,
    CONSTRAINT Cars_PK PRIMARY KEY(ID),
    CONSTRAINT Cars_FK_Vehicles FOREIGN KEY(ID, [Type])
        REFERENCES dbo.Vehicles(ID, [Type])
);
GO
-- adding parent rows
INSERT INTO dbo.Vehicles(ID, [Type]) 
VALUES(1, 'Car'),
(2, 'Truck');
Run Code Online (Sandbox Code Playgroud)

通过INSERT添加子行没有问题,如下所示:

INSERT INTO dbo.Cars(ID, OtherData)
VALUES(1, 'Some Data');

DELETE FROM dbo.Cars;
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,MERGE无法添加一个子行:

MERGE dbo.Cars AS TargetTable
    USING 
        ( SELECT    1 AS ID ,
                    'Some Data' AS OtherData
        ) AS SourceData
    ON  SourceData.ID = TargetTable.ID
    WHEN NOT MATCHED 
        THEN INSERT (ID, OtherData)
        VALUES(SourceData.ID, SourceData.OtherData);

Msg 547, Level 16, State 0, Line 1
The MERGE statement conflicted with the FOREIGN KEY constraint "Cars_FK_Vehicles". The conflict occurred in database "Test", table "dbo.Vehicles".
The statement has been terminated.
Run Code Online (Sandbox Code Playgroud)

这是MERGE中的错误还是我错过了什么?

Mar*_*ith 10

看起来像是一个明确的错误MERGE.

执行计划具有Clustered Index Merge运算符,并且应该输出[Cars].ID,[Cars].Type以对Vehicles表进行验证.

实验表明,不是传递值"Car"作为Type值传递空字符串.这可以通过删除车辆然后插入的检查约束来看出

INSERT INTO dbo.Vehicles(ID, [Type]) VALUES (3, '');
Run Code Online (Sandbox Code Playgroud)

以下声明现在有效

MERGE dbo.Cars AS TargetTable
    USING 
        ( SELECT    3 AS ID ,
                    'Some Data' AS OtherData
        ) AS SourceData
    ON  SourceData.ID = TargetTable.ID
    WHEN NOT MATCHED 
        THEN INSERT (ID, OtherData)
        VALUES(SourceData.ID, SourceData.OtherData);
Run Code Online (Sandbox Code Playgroud)

但最终结果是它插入了违反FK约束的行.

汽车

ID          Type  OtherData
----------- ----- ----------
3           Car   Some Data
Run Code Online (Sandbox Code Playgroud)

车辆

ID          Type
----------- -----
1           Car
2           Truck
3           
Run Code Online (Sandbox Code Playgroud)

之后立即检查约束

DBCC CHECKCONSTRAINTS  ('dbo.Cars')
Run Code Online (Sandbox Code Playgroud)

显示违规行

Table         Constraint          Where
------------- ------------------- ------------------------------
[dbo].[Cars]  [Cars_FK_Vehicles]  [ID] = '3' AND [Type] = 'Car'
Run Code Online (Sandbox Code Playgroud)