Usuário com melhor resposta
Que erro e esse ( Trigger)

Pergunta
-
Prezados fiz essa Trigger para poder fazer um insert (Update) num campo de uma tabela, a trigger foi criado sem erro, porem quando eu faço o lançamento na tabela me retorna uma mensagem de erro.
TRIGGER
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER TRIGGER [RESULTADO] ON [dbo].[MTRFCOMPL]
FOR INSERT
AS
DECLARE @IDPRJ INT
DECLARE @IDTRF INT
DECLARE CURSORIDPRJ CURSOR FOR
SELECT isnull(convert(decimal(10,3), T),0) * isnull(convert(decimal(10,3), Y01),0)
* isnull(convert(decimal(10,3), Y02),0) AS [RESULTADO],
Y01,Y02,Y03,Y04,RES FROM MTRFCOMPL
OPEN CURSORIDPRJ
FETCH NEXT FROM CURSORIDPRJ INTO @IDPRJ,@IDTRF
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE MTRFCOMPL SET RES =
isnull(convert(decimal(10,3), T),0) * isnull(convert(decimal(10,3), Y01),0)* isnull(convert(decimal(10,3), Y02),0)
FROM MTRFCOMPL
WHERE IDPRJ = @IDPRJ AND IDTRF = @IDTRF
FETCH NEXT FROM CURSORIDPRJ INTO @IDPRJ
END
CLOSE CURSORIDPRJ
DEALLOCATE CURSORIDPRJ
mensagem de erro
General SQL error.
Cursorfetch: The number of variables declared in the INTO list must match that of selected columns.Com isso o sistema nao me permite salver. agradeço a ajuda de todos vcs.
Respostas
-
Olá,
Você está melhorando, mas ainda falta um pouco mais a ser feito. Quando a idéia é trabalhar com linhas, você não deve fazer a declaração de variáveis, pois, isso irá levar a problemas (o artigo inclusive fala sobre isso). Retire a declaração de variáveis e a cláusula WHERE e inclua um JOIN com a INSERTED. Assim todas as linhas são contempladas sem a necessidade de cursor. Ex:
UPDATE MTRF SET CAMPOLIVREVALOR1 = isnull(convert(decimal(10,3), MT.Y01),0) * isnull(convert(decimal(10,3), MT.Y02),0) FROM MTRF INNER JOIN MTRFCOMPL AS MT ON MT.CODCOLIGADA = MTRF.CODCOLIGADA AND MT.IDPRJ = MTRF.IDPRJ AND MT.IDTRF = MTRF.IDTRF INNER JOIN INSERTED AS I ON MT.ID = I.ID AND MT.IDPRJ = I.IDPRJ AND MT.IDTRF = I.IDTRF
Se você necessita trocar, então a trigger não deve ser somente para eventos de INSERT, mas também para eventos de UPDATE.
[ ]s,
Gustavo Maia Aguiar
http://gustavomaiaaguiar.spaces.live.comComo descobrir a data do último acesso a uma tabela ?
http://gustavomaiaaguiar.spaces.live.com/blog/cns!F4F5C630410B9865!964.entry
Classifique as respostas. O seu feedback é imprescindível- Marcado como Resposta Ronnie Von terça-feira, 27 de abril de 2010 19:11
Todas as Respostas
-
Você está declarando o cursor com as 6 colunas [RESULTADO],Y01,Y02,Y03,Y04,RES .
Entretanto na hora de atribuir esses valores as variáveis, você não está especificando o mesmo número de variáveis e colunas do cursor.
FETCH NEXT FROM CURSORIDPRJ INTO @IDPRJ,@IDTRF -- só 2 variáveis
e
FETCH NEXT FROM CURSORIDPRJ INTO @IDPRJ -- só 1 variável
Fabrício França Lima | MCP, MCTS, MCITP | Visite meu site: http://fabriciodba.spaces.live.com/ -
Fabricio bom dia, fiz a alteração conforme vc tinha bem observado, porem o mensagem de erro continua aparecendo
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER TRIGGER [RESULTADO] ON [dbo].[MTRFCOMPL]
FOR INSERT
AS
DECLARE @IDPRJ INT
DECLARE @IDTRF INT
DECLARE CURSORIDPRJ CURSOR FOR
SELECT isnull(convert(decimal(10,3), T),0) * isnull(convert(decimal(10,3), Y01),0)
* isnull(convert(decimal(10,3), Y02),0) AS [RESULTADO]
FROM MTRFCOMPL
OPEN CURSORIDPRJ
FETCH NEXT FROM CURSORIDPRJ INTO @IDPRJ,@IDTRF
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE MTRFCOMPL SET RES =
isnull(convert(decimal(10,3), T),0) * isnull(convert(decimal(10,3), Y01),0)* isnull(convert(decimal(10,3), Y02),0)
FROM MTRFCOMPL
WHERE IDPRJ = @IDPRJ AND IDTRF = @IDTRF
FETCH NEXT FROM CURSORIDPRJ INTO @IDPRJ,@IDTRF
END
CLOSE CURSORIDPRJ
DEALLOCATE CURSORIDPRJmensagem de erro
mensagem de erro
General SQL error.
Cursorfetch: The number of variables declared in the INTO list must match that of selected columns.obrigado pela ajuda
-
Ronnie,
Agora você está montando o cursor com 1 coluna [RESULTADO] e está tentando atribuir valores a 2 variáveis @IDPRJ,@IDTRF .
Tira uma dessas e verifica se o erro continua.
Fabrício França Lima | MCP, MCTS, MCITP | Visite meu site: http://fabriciodba.spaces.live.com/ Novo Post: Criando um CheckList Automático do Banco de Dados -
Ronni von,
a consulta do cursor está retornando apenas um resultado e o fetch precisa de 2. O select do cursor só tem o valor abaixo:
isnull(convert(decimal(10,3), T),0) * isnull(convert(decimal(10,3), Y01),0)
* isnull(convert(decimal(10,3), Y02),0) AS [RESULTADO]
Se a resposta resolveu sua questão ou problema, classifique-a para manter a qualidade do forum e a confiabilidade dos participantes.
Alex M. Bastos
http://bastosalex.spaces.live.com
-
Prezados, Alex, e Fabricio, mudei essa trigger conforme as explicaçoes de vcs, quando eu incluo o lançamento nao me aparece mais o erro, porem o campo que deveria receber o calculo que e RES, nao esta recebendo,
ele so recebe a informação quando eu vou na trigger e executo o Update ai ele atualiza,
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER TRIGGER [RESULTADO] ON [dbo].[MTRFCOMPL]
FOR INSERT
AS
DECLARE @IDPRJ INT
DECLARE @IDTRF INT
DECLARE CURSORIDPRJ CURSOR FOR
SELECT IDPRJ,isnull(convert(decimal(10,3), T),0) * isnull(convert(decimal(10,3), Y01),0)
* isnull(convert(decimal(10,3), Y02),0) AS [RESULTADO]
FROM MTRFCOMPL
OPEN CURSORIDPRJ
FETCH NEXT FROM CURSORIDPRJ INTO @IDPRJ,@IDTRF
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE MTRFCOMPL SET RES =
isnull(convert(decimal(10,3), T),0) * isnull(convert(decimal(10,3), Y01),0)* isnull(convert(decimal(10,3), Y02),0)
FROM MTRFCOMPL
WHERE IDPRJ = @IDPRJ AND IDTRF = @IDTRF
FETCH NEXT FROM CURSORIDPRJ INTO @IDPRJ,@IDTRF
END
CLOSE CURSORIDPRJ
DEALLOCATE CURSORIDPRJNao era para ser automatico, atualizar no momento que mando salvar.
Obrigado a todos
-
Ronnie Von,
a variável @IDTRF do cursor é int, mas o select do cursor retorna data type decimal para esta variável. Isto está correto?
Para ver se a trigger está sendo disparada, eu criaria uma tabela de log e faria um INSERT nela quando o trigger fosse disparado colocando os valores que está manuseando no trigger.
Além disso, o trigger só é disparado quando dá o commit da transação que o disparou. Depois do insert vc dá commit ou rollback?
Coloque aqui o resultado do teste do log para podermos continuar lhe ajudando.
Se a resposta resolveu sua questão ou problema, classifique-a para manter a qualidade do forum e a confiabilidade dos participantes.
Alex M. Bastos
http://bastosalex.spaces.live.com
-
Bom Dia,
Acredito que ao invés de tentarmos descobrir porque o cursor não está funcionando seja muito mais efetivo postar uma solução mais performática, pois, nesse caso o CURSOR é completamente desnecessário além do que há possíveis erros de lógica. A leitura do código me parece a seguinte:
Para cada registro em MTRFCOMPL
Atualize a tabela MTRFCOMPL onde a coluna IDPRJ e IDTRF seja igual ao do registo capturado
FimNão entendi porque varrer a tabela MTRFCOMPL e atualizá-la dentro de uma trigger. Isso será redudante e muito pouco performático, pois, em outras palavras, para cada INSERT, a tabela inteira será varrida e atualizada (não há filtros no cursor). E se fosse essa a lógica, bastaria um simples comando de UPDATE. Além de mais eficiente, representa muito menos código o que reflete menor dificuldade de manutenção. Sugiro a leitura do artigo abaixo:
Piores Práticas – Elaborar triggers preparadas para linhas e não para conjuntos
http://gustavomaiaaguiar.spaces.live.com/blog/cns!F4F5C630410B9865!937.entry[ ]s,
Gustavo Maia Aguiar
http://gustavomaiaaguiar.spaces.live.comComo descobrir a data do último acesso a uma tabela ?
http://gustavomaiaaguiar.spaces.live.com/blog/cns!F4F5C630410B9865!964.entry
Classifique as respostas. O seu feedback é imprescindível- Sugerido como Resposta Alex M. Bastos sexta-feira, 26 de março de 2010 17:53
-
OLa Pessoal, tentando explicar melhor essa trigger, tenho na tabela MTRFCOMPL os seguinte campos T,Y01,Y02, O resultado desse calculo deveria ser inserido na Coluna UPDATE MTRFCOMPL SET RES,
a minha intencao com essa trigger e fazer isso,
Obrigado a todos
-
Bom Dia,
De fato o cursor não é necessário nesse caso. Veja o exemplo abaixo:
-- Cria a tabela CREATE TABLE T (ID INT, C1 INT, C2 INT, C3 INT) GO -- Cria a trigger CREATE TRIGGER TR ON T FOR INSERT AS -- O uso da INSERTED irá impedir que linhas que já estejam atualizadas sejam atualizadas de novo -- Atualizar as linhas de novo é ineficiente UPDATE T SET T.C3 = T.C1 + T.C2 FROM T INNER JOIN INSERTED AS I ON T.ID = I.ID GO -- Insere um registro INSERT INTO T (ID, C1, C2) VALUES (1, 2, 2) -- Verifica o retorno (o cálculo foi feito) SELECT ID, C1, C2, C3 FROM T -- Insere dois registros INSERT INTO T (ID, C1, C2) SELECT 2, 3, 4 UNION ALL SELECT 3, 5, 6 -- Verifica o retorno (o cálculo foi feito) SELECT ID, C1, C2, C3 FROM T
Analisando melhor, nem a trigger talvez seja de fato necessária.
-- Dropa a coluna com o cálculo ALTER TABLE T DROP COLUMN C3 -- Refaz a coluna para uma coluna calculada ALTER TABLE T ADD C3 As C1 + C2 -- Verifica o cálculo SELECT ID, C1, C2, C3 FROM T
E analisando melhor ainda, nem a coluna calculada é de fato necessária.
CREATE VIEW V AS SELECT ID, C1, C2, C1 + C2 As C3 FROM T GO SELECT ID, C1, C2, C3 FROM V
[ ]s,
Gustavo Maia Aguiar
http://gustavomaiaaguiar.spaces.live.comComo descobrir a data do último acesso a uma tabela ?
http://gustavomaiaaguiar.spaces.live.com/blog/cns!F4F5C630410B9865!964.entry
Classifique as respostas. O seu feedback é imprescindível- Sugerido como Resposta Alex M. Bastos sexta-feira, 26 de março de 2010 17:53
-
Ola Pessoal Desculpa a minha Ignorancia, mas esta complicado, Gustavo olhando no seu Blog, no topico Elaborar triggers preparadas para linhas e não para conjuntos,
fiz uma aqui baseado na seu exemplo, e tb nao funcionou,
Veja como ficou
-- "Prepara" a trigger para operar múltiplas linhas
ALTER TRIGGER [RES] ON [dbo].[MTRFCOMPL]
FOR INSERT
AS
BEGIN
-- Declara as variáveis para atualização
DECLARE @IDPRJ INT, @IDTRF INT-- Declara um cursor para "varrer" a INSERTED
DECLARE RESULT CURSOR
FAST_FORWARD
FOR SELECT
isnull(convert(decimal(10,3), Y01),0) *
isnull(convert(decimal(10,3), Y02),0)
FROM MTRFCOMPL WHERE IDPRJ = '192'/* ProdutoID, Quantidade, DataVenda FROM INSERTED*/
-- É necessário ordenar para evitar que uma venda mais antiga atualize a data erroneamente
ORDER BY IDPRJ, IDTRF-- Abre o cursor
OPEN RESULT-- Lê o primeiro registro
FETCH NEXT FROM MTRFCOMPL INTO @IDPRJ, @IDTRF-- Varre os demais registros
WHILE @@FETCH_STATUS = 0
BEGIN
-- Atualiza o estoque
UPDATE MTRFCOMPL SET RES =
isnull(convert(decimal(10,3), Y01),0) *
isnull(convert(decimal(10,3), Y02),0)
FROM MTRFCOMPL
WHERE @IDPRJ = IDPRJ AND @IDTRF = IDTRF-- Passa para o próximo registro
FETCH NEXT FROM MTRFCOMPL INTO @IDPRJ, @IDTRF
END-- Fecha o cursor
CLOSE RESULT-- Desaloca o cursor
DEALLOCATE RESULT
ENDobrigado a todos
-
Bom Dia,
A idéia do artigo é justamente evitar cursores (veja que ao final tem soluções com um único update).
Qual é a chave primária dessa tabela ? Você chegou a ver os exemplos que coloquei nesse post para evitar o cursor ?[ ]s,
Gustavo Maia Aguiar
http://gustavomaiaaguiar.spaces.live.comComo descobrir a data do último acesso a uma tabela ?
http://gustavomaiaaguiar.spaces.live.com/blog/cns!F4F5C630410B9865!964.entry
Classifique as respostas. O seu feedback é imprescindível -
Ola Gustavo, As chaves primarias Sao os ID, IDPRJ, IDTRF, Vendo alguns exemplo no blog, consegui fazer um aqui sam usar Cursor, veja como ficou
ALTER TRIGGER [RESULTADO] ON [dbo].[MTRFCOMPL]
FOR INSERT
AS
BEGIN
DECLARE @IDPRJ INT , @IDTRF INT
SET @IDPRJ = (SELECT IDPRJ FROM INSERTED)
SET @IDTRF = (SELECT IDTRF FROM INSERTED)
-- Atualiza a tabela de produtos
UPDATE MTRF SET CAMPOLIVREVALOR1 =
isnull(convert(decimal(10,3), MT.Y01),0) *
isnull(convert(decimal(10,3), MT.Y02),0)
FROM MTRF
INNER JOIN MTRFCOMPL AS MT ON MT.CODCOLIGADA = MTRF.CODCOLIGADA AND MT.IDPRJ = MTRF.IDPRJ AND MT.IDTRF = MTRF.IDTRF
WHERE MTRF.IDPRJ = @IDPRJ AND MTRF.IDTRF = @IDTRF
END-----------
Ela faz o calculos corretos, Tipo Coloca na coluna Y01 10 * Y02 10 me retorna no campo CAMPOLIVREVALOR1 = 100.
porem essas informaçoes da coluna Y01 e Y02 eu posso esta trocando a qualquer momento porem mesmo eu trocando ele mantem no campo CAMPOLIVREVALOR1 100.
esse CAMPOLIVREVALOR1 deveria aceitar receber o resultado.
fui clero
obrigado
-
Olá,
Você está melhorando, mas ainda falta um pouco mais a ser feito. Quando a idéia é trabalhar com linhas, você não deve fazer a declaração de variáveis, pois, isso irá levar a problemas (o artigo inclusive fala sobre isso). Retire a declaração de variáveis e a cláusula WHERE e inclua um JOIN com a INSERTED. Assim todas as linhas são contempladas sem a necessidade de cursor. Ex:
UPDATE MTRF SET CAMPOLIVREVALOR1 = isnull(convert(decimal(10,3), MT.Y01),0) * isnull(convert(decimal(10,3), MT.Y02),0) FROM MTRF INNER JOIN MTRFCOMPL AS MT ON MT.CODCOLIGADA = MTRF.CODCOLIGADA AND MT.IDPRJ = MTRF.IDPRJ AND MT.IDTRF = MTRF.IDTRF INNER JOIN INSERTED AS I ON MT.ID = I.ID AND MT.IDPRJ = I.IDPRJ AND MT.IDTRF = I.IDTRF
Se você necessita trocar, então a trigger não deve ser somente para eventos de INSERT, mas também para eventos de UPDATE.
[ ]s,
Gustavo Maia Aguiar
http://gustavomaiaaguiar.spaces.live.comComo descobrir a data do último acesso a uma tabela ?
http://gustavomaiaaguiar.spaces.live.com/blog/cns!F4F5C630410B9865!964.entry
Classifique as respostas. O seu feedback é imprescindível- Marcado como Resposta Ronnie Von terça-feira, 27 de abril de 2010 19:11
-