Sql server 插入的表在使用带有INSTEAD OF INSERT触发器的视图时出错

Sql server 插入的表在使用带有INSTEAD OF INSERT触发器的视图时出错,sql-server,tsql,sql-server-2016,Sql Server,Tsql,Sql Server 2016,我正在尝试运行以下merge语句以插入行: MERGE sales.Widget USING ( VALUES ('19668651', 4.75)) AS widg (WidgetId, WidgetCost) ON 1=0 WHEN NOT MATCHED THEN INSERT (WidgetId, WidgetCost) VALUES (widg.WidgetId, widg.WidgetCost) OUTPUT INSERTED.Widget

我正在尝试运行以下merge语句以插入行:

MERGE sales.Widget 
USING (
    VALUES ('19668651', 4.75))
    AS widg (WidgetId, WidgetCost) 
    ON 1=0
WHEN NOT MATCHED THEN
    INSERT (WidgetId, WidgetCost)
    VALUES (widg.WidgetId, widg.WidgetCost)
OUTPUT INSERTED.WidgetId
    INTO @inserted;
GO
我被我得到的错误弄糊涂了:

不允许列引用“inserted.WidgetId”,因为它引用的基表在此语句中未被修改

我认为
inserted
表只是传递给merge语句的值的内存表

那么,只要传入值,它为什么会关心我是否在修改“基”表呢

我可以清楚地看出,这与这样一个事实有关:我的视图上有一个
触发器,而不是INSERT
触发器(因为它在正常表中工作正常)


但是为什么SQL Server不只是返回传入的值呢?(在本例中为WidgetId。)


以下是重现错误的脚本:

CREATE SCHEMA sales
GO

-- Create the base table
CREATE TABLE sales.Widget_OLD(
    WIDGET_ID int NOT NULL,
    WIDGET_COST money NOT NULL
    CONSTRAINT PK_Widget PRIMARY KEY CLUSTERED (WIDGET_ID ASC) 
) 
GO

-- Create the overlay view
CREATE VIEW sales.Widget AS
    SELECT  widg.WIDGET_ID AS WidgetId, widg.WIDGET_COST AS WidgetCost
    FROM    sales.Widget_OLD widg
GO

-- create the instead of insert trigger

CREATE TRIGGER sales.InsertWidget ON sales.Widget
INSTEAD OF INSERT AS
BEGIN
    INSERT INTO sales.Widget_OLD (WIDGET_ID, WIDGET_COST)
    SELECT  Inserted.WidgetId, inserted.WidgetCost
    FROM    Inserted
END
GO

DECLARE @inserted TABLE (WidgetId varchar(11) NOT null);

MERGE sales.Widget 
USING (
    VALUES ('19668651', 4.75))
    AS widg (WidgetId, WidgetCost) 
    ON 1=0
WHEN NOT MATCHED THEN
    INSERT (WidgetId, WidgetCost)
    VALUES (widg.WidgetId, widg.WidgetCost)
OUTPUT INSERTED.WidgetId
    INTO @inserted;
GO

-- Clean up
DROP TRIGGER sales.InsertWidget 
DROP VIEW sales.Widget
DROP TABLE sales.Widget_OLD
DROP SCHEMA sales
go

注意:这是我的Entity Framework Core应用程序,当我尝试进行3+插入()时,问题是关于如何阻止EF Core使用
MERGE
。这是为了了解发生了什么。

“但是为什么SQL Server不只是返回传入的值?”因为插入的
不是指传入的值,而是指实际插入的值。换句话说,它必须推迟生成这些值,直到触发器实际确定它们是什么。这与仅仅输出输入大不相同,即使在这种情况下,触发器碰巧没有更改值,而且显然非常复杂,不支持这种特定场景。此外,为什么要使用
merge
来实现简单的
insert
?@ZoharPeled-简短回答:这是生成的代码。冗长的回答:当需要插入的行数超过3行时,一个名为Entity Framework Core(由Microsoft提供)的产品会为插入生成这样的代码。对于这个问题,我已经简化为一行,但是原始查询通过合并插入了3行。较长的答案:请参阅问题底部的链接,了解完整的细节和解决方法(作为答案)。