m.r.m.40 Ответов: 1

Подзапрос вернул более 1 значения. Msg 512, уровень 16


Привет,
У меня есть триггер и две таблицы следующим образом,
Исходная Таблица TInfo:
CREATE TABLE [dbo].[TInfo] (
	[F_Code] [Int_Positive] IDENTITY (1, 1) NOT FOR REPLICATION  NOT NULL ,
	[FirstName] [varchar] (256),
	[LastName] [varchar] (256),
	[Guid] [uniqueidentifier] NOT NULL 
) ON [PRIMARY]

Перенос Триггера TInfoDeleteTrigger Который должен записывать все строки, которые будут удалены из исходной таблицы:
CREATE TRIGGER TInfoDeleteTrigger ON [dbo].[TArtikl] 
AFTER DELETE 
AS
BEGIN
DECLARE @tempGUID UNIQUEIDENTIFIER
set @tempGUID = (SELECT GUID FROM DELETED)

INSERT INTO TInfo_Performance_Queue 
(F_Cod, FirstName, LastName, Guid, username, operation, datetime,
 editionno)---two edition number variables

SELECT
 F_Cod, FirstName, LastName, Guid, System_user, 'Delete row from TInfo', GetDate(),
 (SELECT dbo.GetMaxEditionNo(@tempGUID))
FROM    DELETED      
END

Функция GetMaxEditionNo Который должен считывать максимальный номер издания записи:
The scenario of the edition number is to know how many time a record has beed updated through the application, I also have triggers for other operations but the problem is with the delete operation.

CREATE FUNCTION dbo.GetMaxEditionNo(@GUID UNIQUEIDENTIFIER) 
RETURNS INT  AS  
BEGIN 
	DECLARE @EditionNo int
	SET @EditionNo = (SELECT MAX(editionno) FROM TInfo_Performance_Queue WHERE TInfo_Performance_Queue.GUID = @GUID)
RETURN @EditionNo
END

Назначение Настольный TInfo_Performance_Queu:
CREATE TABLE [dbo].[TInfo_Performance_Queue] (
	[F_Cod] [bigint] NULL ,
	[FirstName] [varchar] (256),
	[LastName] [varchar] (256)
	[Guid] [uniqueidentifier] NULL ,
	[username] [nvarchar] (256) COLLATE Arabic_CI_AS NULL ,
	[operation] [nvarchar] (256) COLLATE Arabic_CI_AS NULL ,
	[datetime] [datetime] NULL ,
	[editionno] [int] NULL 
)


Если я удаляю строку вручную, все в порядке, и все идет так, как я ожидаю, но если я попытаюсь удалить строку с помощью GUID строки, триггер остановится из-за следующей ошибки:

Delete from TInfo where Guid = '{0B08A4F5-13A9-4417-992A-312B0F6CC310}'
Server: Msg 512, Level 16, State 1, Procedure TInfoDeleteTrigger, Line 7
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The statement has been terminated.



Я не могу найти источник ошибки и пока не могу ее решить.

Что я уже пробовал:

Ну, я читаю возможные способы решить эту проблему, но пока не могу ее исправить.

1 Ответов

Рейтинг:
2

Wendelius

Насколько я вижу, проблема заключается в том, что один DELETE оператор может удалять несколько строк. В таком случае спусковой крючок срабатывает только один раз и deleted таблица содержит одну строку для каждой удаленной строки. Поэтому, когда вы извлекаете значение из deleted таблица вы получаете много строк.

Вот упрощенный тестовый случай

CREATE TABLE TriggerTest (
   col1 int
);

CREATE TRIGGER trg_TriggerTest_Delete ON TriggerTest
AFTER DELETE AS
BEGIN
  DECLARE @col1 int;
  SET @col1 = (SELECT col1 FROM DELETED);
  PRINT @col1;
END;

-- add five rows
INSERT INTO TriggerTest (col1) values 
(1), (2), (3), (4), (5)

-- deleting a single row succeeds
DELETE FROM TriggerTest WHERE col1 = 2;

-- deleting multiple rows fails
DELETE FROM TriggerTest WHERE col1 IN (3,4);

Последнее удаление возвращается с
Msg 512, Level 16, State 1, Procedure trg_TriggerTest_Delete, Line 5 [Batch Start Line 20]
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

В качестве исправления я бы попытался удалить переменную в первую очередь. Если вы выбираете данные на основе удаленных строк, не могли бы вы просто иметь что-то вроде

CREATE TRIGGER TInfoDeleteTrigger ON [dbo].[TArtikl] 
AFTER DELETE 
AS
BEGIN
   INSERT INTO TInfo_Performance_Queue 
   (F_Cod, FirstName, LastName, Guid, username, operation, datetime, editionno)
   ---two edition number variables

   SELECT
      F_Cod, FirstName, LastName, Guid, System_user, 
      'Delete row from TInfo', GetDate(),
      dbo.GetMaxEditionNo(deleted.Guid)
   FROM    DELETED      
END


[ДОБАВЛЕН]
Еще один пример, включающий столбец guid
CREATE TABLE TriggerTest (
   col1 int,
   Guidcol uniqueidentifier default newid()
);

CREATE TRIGGER trg_TriggerTest_Delete ON TriggerTest
AFTER DELETE AS
BEGIN
  SELECT deleted.guidcol from deleted;
END;

-- add five rows
INSERT INTO TriggerTest (col1) values 
(1), (2), (3), (4), (5)


-- delete few rows
DELETE FROM TriggerTest WHERE col1 IN (3,4);

Выполняется удаление производит выход, как
guidcol
-------
4F1D6049-0558-4D2F-A81A-E207D8AC1795
F6B88232-3326-4F7C-8D36-64ED9F3CC826


m.r.m.40

Большое вам спасибо за ваше прекрасное объяснение.
К Сожалению, Удалено.Guid не работал.

Wendelius

Почему не сработал Селект?

Я изменил ответ, включив в него пример использования uniqueidentifier. Тест проходит без ошибок, но ваша ситуация как-то отличается?

m.r.m.40

Есть строки с одним и тем же идентификатором GUID. может ли это быть причиной проблемы?

m.r.m.40

Поскольку есть строки с одинаковым GUID из-за их регистрационного документа, я изменил их на строки, которые заполняют переменные триггеров, таким образом:

Объявить @tempGUID UNIQUEIDENTIFIER
set @tempGUID = (выберите верхний 1 GUID из удаленных)
Объявить @tempF_Cod INT
set @tempF_Cod =(SELECT TOP 1 F_Cod FROM DELETED)

Похоже, что проблема была решена, так как до сих пор она работает должным образом.

Wendelius

Поскольку я не знаю бизнес-требований, я не могу сказать, правильно это или нет, но у меня есть сомнения.

Рассмотрим ситуацию, когда удаляются пять строк. Триггер срабатывает только один раз, и вы получаете только один guid (первый). После этого вы вставляете в TInfo_Performance_Queue возвращаемое значение из GetMaxEditionNo. Таким образом, все пять строк имеют одинаковое значение для editionno.

Это действительно так?

Если нет, можете ли вы опубликовать подробную информацию (код плюс ошибка) о проблеме в предыдущем подходе?

m.r.m.40

каждая строка существует в соответствии с регистрационным документом. таким образом, у них есть GUID документа. И каждый документ (любая строка таблицы TDocument) имеет много строк в таблице TInfo, возможно, что оператор программного приложения (не DBAdmin или оператор DB) пытается обновить или удалить информацию документа этот сценарий разрабатывается путем выполнения SP, который удаляет всю информацию документа, поэтому я знаю, что каждый раз, когда SP выполняется, будут удалены только строки уникального GUID. (Не знаю, смогу ли я объяснить ситуацию или нет.)
Еще раз, спасибо за вашу помощь.

Wendelius

Звучит хорошо. Главное, чтобы у вас все получилось :)