SQL Server 无法插入启用触发器的表中
Posted
技术标签:
【中文标题】SQL Server 无法插入启用触发器的表中【英文标题】:SQL Server cant insert into table with trigger enabled 【发布时间】:2019-10-22 14:46:40 【问题描述】:我有一个表,其中我只能有 2 行状态为激活 (1),所以我有一个可以限制它的触发器。
这是触发器:
ALTER TRIGGER [dbo].[ciclo_OI]
ON [dbo].[ciclo]
FOR INSERT
AS
BEGIN
SET NOCOUNT ON
IF (SELECT COUNT(*) FROM ciclo WHERE cicloEstado = 1) > 2
ROLLBACK TRANSACTION
END
GO
问题是当我尝试在表格中插入一些东西时,我得到了这个错误:
消息 334,第 16 级,状态 1,第 1 行 如果 DML 语句的目标表 'ciclo' 包含没有 INTO 子句的 OUTPUT 子句,则该语句不能有任何启用的触发器。
我能做些什么来解决这个问题?
【问题讨论】:
你能显示导致错误的插入语句吗? 如果您要回滚事务,通知插入这些行的过程不是很好吗?你知道 - 所以它至少可以捕获(并可能响应)错误? 而且报错信息很清楚。不要在插入语句中使用输出子句,在输出子句中使用 into 选项,或者更改捕获错误的方法。 larnu 的演示和讨论here 【参考方案1】:不要为此使用触发器。使用过滤的唯一索引会更好:
CREATE UNIQUE INDEX UQ_one_cicloEstado
ON dbo.ciclo_OI (cicloEstado)
WHERE cicloEstado = 1;
例子:
CREATE TABLE dbo.TestTable (ID int IDENTITY,
SomeInt int,
SomeString varchar(10));
CREATE UNIQUE INDEX UQ_one_SomeInt
ON dbo.TestTable (SomeInt)
WHERE SomeInt = 1;
GO
INSERT INTO dbo.TestTable (SomeInt,
SomeString)
VALUES(1,'asdkasd'); --Works.
GO
INSERT INTO dbo.TestTable (SomeInt,
SomeString)
VALUES(2,'asdfgdf'); --Works.
GO
INSERT INTO dbo.TestTable (SomeInt,
SomeString)
VALUES(1,'sdfsdf'); --Fails.
GO
INSERT INTO dbo.TestTable (SomeInt,
SomeString)
VALUES(2,'etrytrg'); --Works.
GO
SELECT *
FROM dbo.TestTable;
GO
DROP TABLE dbo.TestTable;
由于 OP 实际上想要 2 行,因此上述内容不正确,但我已将其留在那里。
在我看来,触发器仍然不是最好的地方,但是(不幸的是)它只给我们留下了一个多行标量函数。远非理想,this 可能会受到竞争条件的影响,但我怀疑(由于“2 规则”)这不太可能。这是一个例子:
CREATE TABLE dbo.TestTable (ID int IDENTITY,
SomeInt int,
SomeString varchar(10));
GO
CREATE FUNCTION dbo.CheckInt1Count()
RETURNS INT
AS BEGIN
DECLARE @Count int = 0;
SELECT @Count = COUNT(*)
FROM dbo.TestTable
WHERE SomeInt = 1;
RETURN @Count;
END;
GO
ALTER TABLE dbo.TestTable ADD CONSTRAINT ck_int1Count CHECK (dbo.CheckInt1Count() <= 2);
GO
INSERT INTO dbo.TestTable (SomeInt,
SomeString)
VALUES(1,'asdkasd'); --Works.
GO
INSERT INTO dbo.TestTable (SomeInt,
SomeString)
VALUES(2,'asdfgdf'); --Works.
GO
INSERT INTO dbo.TestTable (SomeInt,
SomeString)
VALUES(1,'sdfsdf'); --Works.
GO
INSERT INTO dbo.TestTable (SomeInt,
SomeString)
VALUES(2,'etrytrg'); --Works.
GO
INSERT INTO dbo.TestTable (SomeInt,
SomeString)
VALUES(1,'jdgfhbsk'); --Fails.
GO
GO
INSERT INTO dbo.TestTable (SomeInt,
SomeString)
VALUES(2,'sdfipasdf'); --Works.
GO
SELECT *
FROM dbo.TestTable;
GO
DROP TABLE TestTable;
DROP FUNCTION dbo.CheckInt1Count;
【讨论】:
我用过,但问题是可以同时激活两条记录(1),所以我不能使用唯一索引 为你添加了一个不同的想法,@ArielPenayo。【参考方案2】:我建议将 count(*) 的结果放入一个变量中,然后查询该变量。
【讨论】:
以上是关于SQL Server 无法插入启用触发器的表中的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 怎么用存触发器实现从一个表里查询数据,然后插入到另一个表里