这个Microsoft Documentation表示“关于引用具有INSTEAD OF触发器的表的INSERT或UPDATE语句何时必须为列提供值的规则与表没有INSTEAD OF触发器的情况相同”。
然而:
CREATE TABLE tbTriggerTest (id INT PRIMARY KEY);
GO
CREATE TRIGGER dbo.tgTriggerTest
ON dbo.tbTriggerTest
INSTEAD OF INSERT
BEGIN
SELECT * FROM INSERTED
END
GO
INSERT tbTriggerTest DEFAULT VALUES
GO
即使在INSERT语句级别我正在向主键中插入空值,也不会抛出错误。事实上,在这种情况下INSERTED.id为NULL。那么文档是不正确的还是它只适用于触发器内?
编辑:响应建议的答案,声明调用者必须为非空列提供一些值,即使它为null,以下内容也不会引发错误,但可能无法提供任何值列ij
。
CREATE TABLE tbTriggerTest2
(
id INT,
ij INT,
CONSTRAINT PK PRIMARY KEY (id, ij)
)
GO
CREATE TRIGGER dbo.tgTriggerTest2
ON dbo.tbTriggerTest2
INSTEAD OF INSERT
AS
BEGIN
SELECT * FROM INSERTED;
END
GO
INSERT tbTriggerTest2 (id) VALUES (0)
GO
答案 0 :(得分:0)
嗯,您引用的docs说:
以下有关INSERT或UPDATE语句的规则 引用具有INSTEAD OF触发器的表必须为其提供值 列与表没有INSTEAD OF的情况相同 触发:
- INSERT语句必须为没有DEFAULT约束的所有NOT NULL列提供值。
问题中的INSERT
声明
INSERT tbTriggerTest DEFAULT VALUES
为所有列提供值。它不会省略任何列。是的,它提供NULL
个值,但文档并未说明INSERT
语句应提供非null 值。它说INSERT
语句应该提到所有非空列。这就是解析器检查的内容 - 列列表。
如果违反INSERT
约束,实际NOT NULL
操作将失败。在您的示例中,实际的INSERT
永远不会发生,因此您不会看到任何错误。
就像你在桌面上没有任何触发器并尝试运行
一样INSERT tbTriggerTest VALUES (NULL)
服务器将解析该语句,看到VALUES
子句与表的列列相同,并尝试执行INSERT
。它将因约束违规而失败。
无法将值NULL插入列'id',表中 'AdventureWorks2014.dbo.tbTriggerTest';列不允许空值。 INSERT失败。声明已经终止。
您可以尝试获得估算的执行计划,然后您将获得一个计划。引擎生成了一个计划并开始执行它。
如果您尝试运行
INSERT tbTriggerTest VALUES (NULL, NULL)
如果没有尝试执行,该语句将失败。
列名或提供的值数与表不匹配 定义
如果你试图获得一个估计的执行计划,你就不会得到一个。引擎无法生成计划,因为列的列表不匹配。
在第二个示例中,id
和ij
列都可以为空。因此,再次,通过触发器或没有触发器,引擎将仅接受具有一个值的INSERT
语句。第二个值将被假定为NULL
。
如果VALUES
子句的列数少于表中的列数,则引擎(或更确切地说,DEFAULT)假定缺少的列为NULL
。因此,在您的示例中,表有两列,语句
INSERT tbTriggerTest2 (id) VALUES (0)
与:
相同INSERT tbTriggerTest2 (id, ij) VALUES (0, NULL)
第二列可以为空,因此它具有默认的NULL
值。您可以指定列的其他默认值,如果您不在列列表中包含此列,INSERT
也将按预期工作。
如果您将表的定义更改为:
CREATE TABLE tbTriggerTest2
(
id INT NOT NULL,
ij INT NOT NULL,
CONSTRAINT PK PRIMARY KEY (id, ij)
)
然后没有触发器,以下语句将失败:
INSERT tbTriggerTest2 (id) VALUES (0)
无法将值NULL插入列'ij',表中 'dbo.tbTriggerTest2';列不允许空值。 INSERT失败。该 声明已被终止。
使用触发器,整个语句将成功运行,因为触发器会禁止尝试将具有NULL
值的行插入到不接受NULL
的列中。
如果您将表的定义更改为:
CREATE TABLE tbTriggerTest3
(
id INT NOT NULL,
ij INT NOT NULL DEFAULT 10
)
然后
INSERT tbTriggerTest3 (id) VALUES (0)
的工作原理如下:
INSERT tbTriggerTest3 (id, ij) VALUES (0, 10)
无论是否触发,它都会成功。
另一方面,
INSERT tbTriggerTest3 (id) VALUES (NULL)
与:
相同INSERT tbTriggerTest3 (id, ij) VALUES (NULL, 10)
如果没有触发器,它将会失败
无法将值NULL插入列'id',表中 'dbo.tbTriggerTest3';列不允许空值。 INSERT失败。
,因为它会尝试将NULL
插入id
,但不接受NULL
使用禁止插入行的触发器,它将成功。