Sql-Server
UPDATE所有行時出錯
當我更新一行時,它工作正常。但是當我更新所有行時:
UPDATE cad_bilhetes SET ligacao_acobrar = 'False'
我收到以下錯誤:
消息 512,級別 16,狀態 1,過程 TG_CAD_BILHETES_UPDATE,第 34 行子查詢返回超過 1 個值。當子查詢跟隨 =、!=、<、<=、>、>= 或子查詢用作表達式時,這是不允許的。該語句已終止。
在 TG_CAD_BILHETES_UPDATE 的第 34 行有:
DECLARE @VALOR_LIGACOES_DDI_ATUAL DECIMAL(7,2)
觸發器的開始:
ALTER TRIGGER [dbo].[TG_CAD_BILHETES_UPDATE] ON [dbo].[CAD_BILHETES] INSTEAD OF UPDATE AS BEGIN DECLARE @ID INT DECLARE @VALOR_BILHETE_NOVO DECIMAL(7,2) DECLARE @VALOR_BILHETE_ATUAL DECIMAL(7,2) DECLARE @ENCONTROU INT DECLARE @ID_CONTRATACAO INT DECLARE @TIPO VARCHAR(2) DECLARE @TIPO_APARELHO VARCHAR(1) DECLARE @ID_COMPETENCIA INT DECLARE @ID_CONTRATACAO_ATUAL INT DECLARE @ID_CONTRATACAO_NOVO INT DECLARE @VALOR_LIGACOES_DDD_FIXO_NOVO DECIMAL(7,2) DECLARE @VALOR_LIGACOES_DDD_MOVEL_NOVO DECIMAL(7,2) DECLARE @VALOR_LIGACOES_LOCAL_MOVEL_NOVO DECIMAL(7,2) DECLARE @VALOR_LIGACOES_LOCAL_FIXO_NOVO DECIMAL(7,2) DECLARE @VALOR_LIGACOES_DDI_NOVO DECIMAL(7,2) DECLARE @VALOR_LIGACOES_VOIP_NOVO DECIMAL(7,2) DECLARE @VALOR_LIGACOES_TOM_REMOTO_NOVO DECIMAL(7,2) DECLARE @VALOR_LIGACOES_DDD_FIXO_ATUAL DECIMAL(7,2) DECLARE @VALOR_LIGACOES_DDD_MOVEL_ATUAL DECIMAL(7,2) DECLARE @VALOR_LIGACOES_LOCAL_MOVEL_ATUAL DECIMAL(7,2) DECLARE @VALOR_LIGACOES_LOCAL_FIXO_ATUAL DECIMAL(7,2) DECLARE @VALOR_LIGACOES_DDI_ATUAL DECIMAL(7,2) DECLARE @VALOR_LIGACOES_VOIP_ATUAL DECIMAL(7,2) DECLARE @VALOR_LIGACOES_TOM_REMOTO_ATUAL DECIMAL(7,2) DECLARE @VALOR_OS_NOVO DECIMAL(7,2) DECLARE @FOI_CANCELADO_NOVO BIT SET @ENCONTROU = 0 SET @ID = (SELECT ID FROM INSERTED) SET @ID_COMPETENCIA = (SELECT ID_COMPETENCIA FROM INSERTED) SET @VALOR_LIGACOES_DDD_FIXO_NOVO = 0 SET @VALOR_LIGACOES_DDD_MOVEL_NOVO = 0 SET @VALOR_LIGACOES_LOCAL_MOVEL_NOVO = 0 SET @VALOR_LIGACOES_LOCAL_FIXO_NOVO = 0 SET @VALOR_LIGACOES_DDI_NOVO = 0 SET @VALOR_LIGACOES_VOIP_NOVO = 0 SET @VALOR_LIGACOES_TOM_REMOTO_NOVO = 0 SET @VALOR_LIGACOES_DDD_FIXO_ATUAL = 0 SET @VALOR_LIGACOES_DDD_MOVEL_ATUAL = 0 SET @VALOR_LIGACOES_LOCAL_MOVEL_ATUAL = 0 SET @VALOR_LIGACOES_LOCAL_FIXO_ATUAL = 0 SET @VALOR_LIGACOES_DDI_ATUAL = 0 SET @VALOR_LIGACOES_VOIP_ATUAL = 0 SET @VALOR_LIGACOES_TOM_REMOTO_ATUAL = 0 SELECT TOP (1) @TIPO = SUBSTRING(B.TIPO, 2, 2), @TIPO_APARELHO = SUBSTRING(B.TIPO, 4, 1), @VALOR_BILHETE_ATUAL = B.VALOR, @ID_CONTRATACAO_ATUAL = C.ID FROM CAD_BILHETES AS B JOIN CAD_CONTRATACAO AS C ON B.ID_PRODUTO = C.ID_PRODUTO AND (B.DATA_HORA >= C.DATA_INICIO AND (C.DATA_FIM IS NULL OR B.DATA_HORA <= C.DATA_FIM)) WHERE B.ID = @ID and C.FOI_CANCELADA= 'FALSE' IF @ID_CONTRATACAO_ATUAL IS NOT NULL BEGIN IF(@TIPO = 'IV') BEGIN SET @VALOR_LIGACOES_VOIP_ATUAL = @VALOR_BILHETE_ATUAL END ELSE IF(@TIPO = 'IT') BEGIN SET @VALOR_LIGACOES_TOM_REMOTO_ATUAL = @VALOR_BILHETE_ATUAL END ELSE IF(@TIPO = 'EL') BEGIN IF(@TIPO_APARELHO = 'F') BEGIN SET @VALOR_LIGACOES_LOCAL_FIXO_ATUAL = @VALOR_BILHETE_ATUAL END ELSE IF(@TIPO_APARELHO = 'M') BEGIN SET @VALOR_LIGACOES_LOCAL_MOVEL_ATUAL = @VALOR_BILHETE_ATUAL END END ELSE IF(@TIPO = 'EN') BEGIN IF(@TIPO_APARELHO = 'F') BEGIN SET @VALOR_LIGACOES_DDD_FIXO_ATUAL = @VALOR_BILHETE_ATUAL END ELSE IF(@TIPO_APARELHO = 'M') BEGIN SET @VALOR_LIGACOES_DDD_MOVEL_ATUAL = @VALOR_BILHETE_ATUAL END END ELSE IF(@TIPO = 'EI') BEGIN SET @VALOR_LIGACOES_DDI_ATUAL = @VALOR_BILHETE_ATUAL END END SELECT @TIPO = SUBSTRING(I.TIPO, 2, 2), @TIPO_APARELHO = SUBSTRING(I.TIPO, 4, 1), @VALOR_BILHETE_NOVO = I.VALOR, @ID_CONTRATACAO_NOVO = C.ID, @FOI_CANCELADO_NOVO = I.FOI_CANCELADO, @ID_COMPETENCIA = I.ID_COMPETENCIA FROM INSERTED AS I JOIN CAD_CONTRATACAO AS C ON I.ID_PRODUTO = C.ID_PRODUTO AND (I.DATA_HORA >= C.DATA_INICIO AND (I.DATA_HORA <= C.DATA_FIM OR C.DATA_FIM IS NULL)) WHERE C.FOI_CANCELADA= 'FALSE' IF @ID_CONTRATACAO_NOVO IS NOT NULL BEGIN IF(@TIPO = 'IV') BEGIN SET @VALOR_LIGACOES_VOIP_NOVO = @VALOR_BILHETE_NOVO END ELSE IF(@TIPO = 'IT') BEGIN SET @VALOR_LIGACOES_TOM_REMOTO_NOVO = @VALOR_BILHETE_NOVO END ELSE IF(@TIPO = 'EL') BEGIN IF(@TIPO_APARELHO = 'F') BEGIN SET @VALOR_LIGACOES_LOCAL_FIXO_NOVO = @VALOR_BILHETE_NOVO END ELSE IF(@TIPO_APARELHO = 'M') BEGIN SET @VALOR_LIGACOES_LOCAL_MOVEL_NOVO = @VALOR_BILHETE_NOVO END END ELSE IF(@TIPO = 'EN') BEGIN IF(@TIPO_APARELHO = 'F') BEGIN SET @VALOR_LIGACOES_DDD_FIXO_NOVO = @VALOR_BILHETE_NOVO END ELSE IF(@TIPO_APARELHO = 'M') BEGIN SET @VALOR_LIGACOES_DDD_MOVEL_NOVO = @VALOR_BILHETE_NOVO END END ELSE IF(@TIPO = 'EI') BEGIN SET @VALOR_LIGACOES_DDI_NOVO = @VALOR_BILHETE_NOVO END SELECT @ENCONTROU = 1 FROM CAD_CUSTO_PRODUTO WHERE ID_CONTRATACAO = @ID_CONTRATACAO_NOVO AND ID_COMPETENCIA=@ID_COMPETENCIA IF(@ENCONTROU = 0) BEGIN INSERT INTO CAD_CUSTO_PRODUTO VALUES (@ID_CONTRATACAO_NOVO, @ID_COMPETENCIA, NULL, 0, 0, 0, @VALOR_LIGACOES_DDD_FIXO_NOVO, @VALOR_LIGACOES_DDD_MOVEL_NOVO, @VALOR_LIGACOES_LOCAL_MOVEL_NOVO, @VALOR_LIGACOES_LOCAL_FIXO_NOVO, @VALOR_LIGACOES_DDI_NOVO, @VALOR_LIGACOES_VOIP_NOVO, @VALOR_LIGACOES_TOM_REMOTO_NOVO) END ELSE BEGIN IF (@FOI_CANCELADO_NOVO = 1) BEGIN UPDATE CAD_CUSTO_PRODUTO SET VALOR_LIGACOES_DDD_FIXO = VALOR_LIGACOES_DDD_FIXO - @VALOR_LIGACOES_DDD_FIXO_ATUAL, VALOR_LIGACOES_DDD_MOVEL = VALOR_LIGACOES_DDD_MOVEL - @VALOR_LIGACOES_DDD_MOVEL_ATUAL, VALOR_LIGACOES_LOCAL_MOVEL = VALOR_LIGACOES_LOCAL_MOVEL - @VALOR_LIGACOES_LOCAL_MOVEL_ATUAL, VALOR_LIGACOES_LOCAL_FIXO = VALOR_LIGACOES_LOCAL_FIXO - @VALOR_LIGACOES_LOCAL_FIXO_ATUAL, VALOR_LIGACOES_DDI = VALOR_LIGACOES_DDI - @VALOR_LIGACOES_DDI_ATUAL, VALOR_LIGACOES_VOIP = VALOR_LIGACOES_VOIP - @VALOR_LIGACOES_VOIP_ATUAL, VALOR_LIGACOES_TOM_REMOTO = VALOR_LIGACOES_TOM_REMOTO - @VALOR_LIGACOES_TOM_REMOTO_ATUAL WHERE ID_CONTRATACAO = @ID_CONTRATACAO_ATUAL AND ID_COMPETENCIA = @ID_COMPETENCIA END ELSE BEGIN UPDATE CAD_CUSTO_PRODUTO SET VALOR_LIGACOES_DDD_FIXO = VALOR_LIGACOES_DDD_FIXO + (@VALOR_LIGACOES_DDD_FIXO_NOVO - @VALOR_LIGACOES_DDD_FIXO_ATUAL), VALOR_LIGACOES_DDD_MOVEL = VALOR_LIGACOES_DDD_MOVEL + (@VALOR_LIGACOES_DDD_MOVEL_NOVO - @VALOR_LIGACOES_DDD_MOVEL_ATUAL), VALOR_LIGACOES_LOCAL_MOVEL = VALOR_LIGACOES_LOCAL_MOVEL + (@VALOR_LIGACOES_LOCAL_MOVEL_NOVO - @VALOR_LIGACOES_LOCAL_MOVEL_ATUAL), VALOR_LIGACOES_LOCAL_FIXO = VALOR_LIGACOES_LOCAL_FIXO + (@VALOR_LIGACOES_LOCAL_FIXO_NOVO - @VALOR_LIGACOES_LOCAL_FIXO_ATUAL), VALOR_LIGACOES_DDI = VALOR_LIGACOES_DDI + (@VALOR_LIGACOES_DDI_NOVO - @VALOR_LIGACOES_DDI_ATUAL), VALOR_LIGACOES_VOIP = VALOR_LIGACOES_VOIP + (@VALOR_LIGACOES_VOIP_NOVO - @VALOR_LIGACOES_VOIP_ATUAL), VALOR_LIGACOES_TOM_REMOTO = VALOR_LIGACOES_TOM_REMOTO + (@VALOR_LIGACOES_TOM_REMOTO_NOVO - @VALOR_LIGACOES_TOM_REMOTO_ATUAL) WHERE ID_CONTRATACAO = @ID_CONTRATACAO_ATUAL AND ID_COMPETENCIA = @ID_COMPETENCIA END END END UPDATE CAD_BILHETES SET ID_PREFIXO = I.ID_PREFIXO, ID_PRODUTO = I.ID_PRODUTO, ID_COMPETENCIA = I.ID_COMPETENCIA, DATA_HORA = I.DATA_HORA, DURACAO = I.DURACAO, TIPO = I.TIPO, NUMERO_EXTERNO = I.NUMERO_EXTERNO, RAMAL = I.RAMAL, SENHA_AUTORIZACAO = I.SENHA_AUTORIZACAO, CODIGO_DEPENDENCIA = I.CODIGO_DEPENDENCIA, CRITICA = I.CRITICA, [STATUS] = I.STATUS, VALOR = I.VALOR, SEQUENCIAL = I.SEQUENCIAL, FOI_TARIFADO = I.FOI_TARIFADO, FOI_CANCELADO = I.FOI_CANCELADO, DURACAO_TARIFACAO = I.DURACAO_TARIFACAO FROM INSERTED AS I WHERE CAD_BILHETES.ID = I.ID END
SET @ID = (SELECT ID FROM INSERTED)
SET @ID_COMPETENCIA = (SELECT ID_COMPETENCIA FROM INSERTED)
這是一個常見的誤解,即每受影響的行觸發一次,而實際上每個 DML 語句只觸發一次觸發器主體**。
在觸發器主體中,
inserted
和deleted
表包含受操作影響的*所有行。*這樣做有(至少)兩個原因:
- 邏輯運算。如果觸發器主體只有一行可用,則在受影響的行集中執行任務將非常痛苦。
- 表現。高效的基於集合的操作可用於一次處理所有受影響的行。
單行觸發器程式碼可能會在很長一段時間內被忽視,因為它可能合法地適用於您的案例,並且僅在有人決定影響不止一行時才會中斷。更糟糕的是,觸發程式碼有可能實際上成功了,並最終做錯事而沒有錯誤。
不幸的是,在編寫觸發器時沒有安全措施可以告訴您此資訊,因此請認為自己很幸運發現了此錯誤!
** 對於閱讀此內容並考慮到 SQL Server 2008+ 的人,請
MERGE
分別觸發 3 種不同類型,因為它實際上只是在同一 T-SQL 語句中執行INSERT
++的事務性“宏”。UPDATE``DELETE