开发者

Is this a bug in MERGE, failing to implement FOREIGN KEY properly?

开发者 https://www.devze.com 2023-04-13 07:04 出处:网络
I am using the following tables to implement subtypes, which is a very common approach: CREATE TABLE dbo.Vehicles(

I am using the following tables to implement subtypes, which is a very common approach:

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');

I have no problem adding a child row via INSERT, as follows:

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

DELETE FROM dbo.Cars;

Surprisingly, MERGE fails to add one child row:

MERGE dbo.Cars AS TargetTable
    USING 
        ( SELECT    1 AS ID ,
                    'Some Data' AS OtherData
        ) AS SourceData
    ON  SourceData.ID = TargetTable.ID
    WHEN NOT MAT开发者_高级运维CHED 
        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.

Is this a bug in MERGE or am I missing something?


Looks like a definite bug in MERGE to me.

The execution plan has the Clustered Index Merge operator and is supposed to output [Cars].ID,[Cars].Type for validation against the Vehicles table.

Experimentation shows that instead of passing the value "Car" as the Type value it is passing an empty string. This can be seen by removing the check constraint on Vehicles then inserting

INSERT INTO dbo.Vehicles(ID, [Type]) VALUES (3, '');

The following statement now works

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);

But the end result is that it inserts a row violating the FK constraint.

Cars

ID          Type  OtherData
----------- ----- ----------
3           Car   Some Data

Vehicles

ID          Type
----------- -----
1           Car
2           Truck
3           

Checking the constraints immediately afterwards

DBCC CHECKCONSTRAINTS  ('dbo.Cars')

Shows the offending row

Table         Constraint          Where
------------- ------------------- ------------------------------
[dbo].[Cars]  [Cars_FK_Vehicles]  [ID] = '3' AND [Type] = 'Car'
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号