SQL Server нельзя вставить в таблицу с включенным триггером - PullRequest
0 голосов
/ 22 октября 2019

У меня есть таблица, в которой я могу иметь только 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

Проблема в том, что когда я пытаюсь вставить что-то в таблицу, я получаю эту ошибку:

Msg 334, Уровень 16, Состояние 1, Строка 1
Целевая таблица 'ciclo' изОператор DML не может иметь никаких включенных триггеров, если он содержит предложение OUTPUT без предложения INTO.

Что можно сделать, чтобы это исправить?

Ответы [ 2 ]

3 голосов
/ 22 октября 2019

Не используйте триггер для этого. Вам будет лучше с отфильтрованным уникальным индексом:

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;

Поскольку ОП на самом деле хочет 2 строки, то вышеприведенное неверно, но я оставил это там.

Триггер все еще не лучшее место для этого, на мой взгляд, но (к сожалению), которое оставляет нам только многострочную скалярную функцию. Далеко от идеала, и этот может пострадать из-за условий гонки, но я подозреваю (из-за "правила 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;
0 голосов
/ 22 октября 2019

Я бы предложил поместить результаты вашего подсчета (*) в переменную и затем запросить переменную.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...