Sql-Server

UPDATE所有行時出錯

  • November 2, 2012

當我更新一行時,它工作正常。但是當我更新所有行時:

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 &gt;= C.DATA_INICIO AND (C.DATA_FIM IS NULL OR B.DATA_HORA &lt;= 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 &gt;= C.DATA_INICIO AND (I.DATA_HORA &lt;= 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 語句只觸發一次觸發器主體**。

在觸發器主體中,inserteddeleted表包含受操作影響的*所有行。*這樣做有(至少)兩個原因:

  1. 邏輯運算。如果觸發器主體只有一行可用,則在受影響的行集中執行任務將非常痛苦
  2. 表現。高效的基於集合的操作可用於一次處理所有受影響的行。

單行觸發器程式碼可能會在很長一段時間內被忽視,因為它可能合法地適用於您的案例,並且僅在有人決定影響不止一行時才會中斷。更糟糕的是,觸發程式碼有可能實際上成功了,並最終做錯事而沒有錯誤

不幸的是,在編寫觸發器時沒有安全措施可以告訴您此資訊,因此請認為自己很幸運發現了此錯誤!

** 對於閱讀此內容並考慮到 SQL Server 2008+ 的人,請MERGE分別觸發 3 種不同類型,因為它實際上只是在同一 T-SQL 語句中執行INSERT++的事務性“宏”。UPDATE``DELETE

引用自:https://dba.stackexchange.com/questions/27366