none
LLamar sp desde trigger insert. RRS feed

  • Pregunta

  • hola grupo :

    Tengo armado un store que recibe una fecha por parametro , y me piden que lo dispare desde un trigger cdo se inserta datos en una tabla que tiene una campo fechaRep 
    ese campo fecha de la tabla debe ir de parametro al store .
    ?
    Se puede hacer , tiene alguna idea ?


    CREATE TRIGGER nombretrigger ON tabla
    FOR INSERT
    AS
    SELECT fechaRep FROM Inserted ......

    //recupero campos y llamo al 

    exec calculoSp fechaRep


    Gracias.
    miércoles, 26 de noviembre de 2014 3:36

Respuestas

  • Sí que se puede, pero ya que el trigger se ejecuta por instrucción, no por fila, tendrías que usar un cursor para llamar al procedimiento por cada fila, aquí tienes un ejemplo:

    CREATE TRIGGER MiTrigger 
    ON Orders FOR INSERT
    AS
    	IF @@ROWCOUNT = 0 RETURN
    	SET NOCOUNT ON
    	DECLARE c CURSOR LOCAL
    	FOR SELECT OrderDate
    	FROM inserted
    	OPEN c
    	
    	DECLARE @OrderDate datetime
    	
    	FETCH NEXT FROM c INTO @OrderDate
    	WHILE @@FETCH_STATUS = 0
    	BEGIN
    		EXEC MiProc @OrderDate
    		FETCH NEXT FROM c INTO @OrderDate
    	END
    	CLOSE c
    	DEALLOCATE c
    	
    GO

    Los cursores son ineficientes, así que probablemente sería mejor hacer en el trigger lo que haría el procedimiento, pero no sólo con una fila, sino con todas.



    Jesús López


    EntityLite a lightweight, database first, micro orm

    • Propuesto como respuesta webJose miércoles, 26 de noviembre de 2014 15:16
    • Marcado como respuesta sebastian viga miércoles, 26 de noviembre de 2014 21:57
    miércoles, 26 de noviembre de 2014 6:10
  • >>

     En conclusión: recomiendo dejar el cursor tal como está en el ejemplo de Jesús. La mayor parte de las veces hará una única iteración, y no merece la pena incurrir en el aumento de complejidad en el mantenimiento del código que se ocasionaría para eliminarlo, a cambio de una minúscula ganancia en eficiencia.

    <<

    Estoy bastante de acuerdo con lo que dice Alberto, en realidad, deshacerse del cursor sólo merecería la pena si se insertaran bastantes registros en una sóla instrucción, y eso suele ser poco habitual.

    Pero ya puestos, podríamos eliminar el cursor haciendo una pequeña optimización para cuando sólo se inserte una fila:

    CREATE TRIGGER MiTrigger 
    ON Orders FOR INSERT
    AS
            DECLARE @RowCount int
            SET @RowCount = @@ROWCOUNT
    	IF @RowCount = 0 RETURN
    	SET NOCOUNT ON
    
            DECLARE @OrderDate datetime
            
            IF @RowCount = 1
            BEGIN
                 SELECT @OrderDate = OrderDate
                 FROM inserted
                 EXEC MiProc @OrderDate
                 RETURN
            END
    
    
    	DECLARE c CURSOR LOCAL
    	FOR SELECT OrderDate
    	FROM inserted
    	OPEN c
    	
    	
    	FETCH NEXT FROM c INTO @OrderDate
    	WHILE @@FETCH_STATUS = 0
    	BEGIN
    		EXEC MiProc @OrderDate
    		FETCH NEXT FROM c INTO @OrderDate
    	END
    	CLOSE c
    	DEALLOCATE c
    	
    GO



    Jesús López


    EntityLite a lightweight, database first, micro orm

    • Marcado como respuesta sebastian viga miércoles, 26 de noviembre de 2014 21:52
    miércoles, 26 de noviembre de 2014 17:54
  • en mi caso es cdo se da de alta una persona en el sistema se guarda en la tabla y luego se ejecutaria el sp. casi siempre es una fila. Puede ser el caso que hay dos alta  a la misma fechahora

    No, si hubiera dos a la misma hora no habría problema siempre que se inserten con dos sentencias INSERT separadas. Cada una de las dos INSERTS dispararía el trigger, y en cada una de las dos veces al trigger le llegaría la pseudo-tabla INSERTED con un único registro.

    El problema ocurriría si insertases varios registros con una única sentencia (puede ser un "insert into tabla(...) values (...),(...)" o un "insert into tabla select columnas from otratabla"). En ese caso sólo se dispararía el trigger una única vez y le llegarían varios registros en la tabla INSERTED. Si quieres ejecutar el SP para cada uno de esos registros, entonces es cuando el cursor se vuelve necesario.

    Si sabes con toda seguridad que tu programa cliente nunca va a insertar más de un registro con un único INSERT, entonces puedes presumir que la tabla INSERTED nunca traerá más de un registro y se puede eliminar el cursor. Pero es una pequeña chapuza; si alguna vez se modifica el código cliente, o se hace alguna operación de mantenimiento que importe varios registros de golpe, el trigger tendrá un comportamiento inadecuado.

    • Marcado como respuesta sebastian viga miércoles, 26 de noviembre de 2014 21:52
    miércoles, 26 de noviembre de 2014 11:14
  •             Buenos dias Sebastian

                          Te paso un ejemplo para realizar el trigger

    createTRIGGER [dbo].[TI_Barrios] ON [dbo].[FacturaFecha]
    WITH EXECUTE AS CALLER
    FOR INSERT
    AS
    BEGIN

           declare @Fecha datetime;

           select @fecha=fecha from inserted;    

           sp_procedimiento(@fecha);
    END

    Saludos

    BEMO

    Paraguay

    • Marcado como respuesta sebastian viga miércoles, 26 de noviembre de 2014 21:52
    miércoles, 26 de noviembre de 2014 12:08
  • >>

    jesus no  entendi porque el cursor , pero porque hace rato no toco sql server . Por cada fila no se ejecutaria el trigger. 

    <<

    Los triggers no se ejecutan por cada fila, se ejecutan por cada instrucción y una instrucción como por ejemplo una del tipo INSERT INTO MiTabla(<lista de campos>) SELECT <lista de campos> FROM ... inserta más de un registro en la tabla, entonces, dentro del trigger tienes todos los registros insertados por la instrucción en la tabla virtual inserted. Por eso lo del cursor, porque hay que ejecutar el procedimiento por cada fila insertada, o sea, por cada fila en la tabla inserted, y la única manera de ejecutar un procedimiento por cada fila en una tabla es usando un cursor. Aunque, como he dicho antes, se podría incluir la lógica del procedimiento en el trigger, pero modificándola para que funcionara para más de una fecha: todas las fechas en la tabla inserted.




    Jesús López


    EntityLite a lightweight, database first, micro orm


    • Editado Jesús López miércoles, 26 de noviembre de 2014 18:01 x
    • Marcado como respuesta sebastian viga miércoles, 26 de noviembre de 2014 21:48
    miércoles, 26 de noviembre de 2014 18:00

Todas las respuestas

  • Sí que se puede, pero ya que el trigger se ejecuta por instrucción, no por fila, tendrías que usar un cursor para llamar al procedimiento por cada fila, aquí tienes un ejemplo:

    CREATE TRIGGER MiTrigger 
    ON Orders FOR INSERT
    AS
    	IF @@ROWCOUNT = 0 RETURN
    	SET NOCOUNT ON
    	DECLARE c CURSOR LOCAL
    	FOR SELECT OrderDate
    	FROM inserted
    	OPEN c
    	
    	DECLARE @OrderDate datetime
    	
    	FETCH NEXT FROM c INTO @OrderDate
    	WHILE @@FETCH_STATUS = 0
    	BEGIN
    		EXEC MiProc @OrderDate
    		FETCH NEXT FROM c INTO @OrderDate
    	END
    	CLOSE c
    	DEALLOCATE c
    	
    GO

    Los cursores son ineficientes, así que probablemente sería mejor hacer en el trigger lo que haría el procedimiento, pero no sólo con una fila, sino con todas.



    Jesús López


    EntityLite a lightweight, database first, micro orm

    • Propuesto como respuesta webJose miércoles, 26 de noviembre de 2014 15:16
    • Marcado como respuesta sebastian viga miércoles, 26 de noviembre de 2014 21:57
    miércoles, 26 de noviembre de 2014 6:10
  • Los cursores son ineficientes, así que probablemente sería mejor hacer en el trigger lo que haría el procedimiento, pero no sólo con una fila, sino con todas.

    Los cursores son ineficientes... pero no más ineficientes que si la misma operación se hiciera desde fuera sin usar cursores. Por ejemplo, si para evitar el cursor recurriésemos a abrir una transacción desde el lado cliente y dentro insertar un registro y a continuación llamar al SP, el resultado no sólo no sería más eficiente sino que de hecho perderíamos algo de eficiencia debido a la comunicación entre el cliente y el servidor.

    Ganaríamos eficiencia si, como dice Jesús, trasladásemos al trigger las operaciones que hace el SP y fuéramos capaces de resolverlas mediante un JOIN con la tabla INSERTED en lugar de usar un cursor (cosa que puede ser factible o no, dependiendo de lo que tenga dentro el SP). Pero sólo sería ventajoso en el caso de que INSERTED tuviese más de un registro, cosa que probablemente ocurrirá en pocas ocasiones, si las inserciones en la tabla que contiene el trigger se hacen mediante sentencias INSERT "corrientes" (de un solo registro cada una). El resultado sería que para evitarnos el cursor y ganar eficiencia en pocas o ninguna ocasiones, habríamos complicado considerablemente el mantenimiento de nuestra aplicación por haber duplicado en dos sitios el contenido del procedimiento, que puede ser potencialmente muy complejo. En conclusión: recomiendo dejar el cursor tal como está en el ejemplo de Jesús. La mayor parte de las veces hará una única iteración, y no merece la pena incurrir en el aumento de complejidad en el mantenimiento del código que se ocasionaría para eliminarlo, a cambio de una minúscula ganancia en eficiencia.


    miércoles, 26 de noviembre de 2014 8:11
  • Gracias Jesús López y gracias Alberto por contestar. Muy buena informacion.

     jesus no  entendi porque el cursor , pero porque hace rato no toco sql server . Por cada fila no se ejecutaria el trigger. 

    en mi caso es cdo se da de alta una persona en el sistema se guarda en la tabla y luego se ejecutaria el sp. 

    casi siempre es una fila. Puede ser el caso que hay dos alta  a la misma fechahora

    Voy a analizar lo de alberto tambien

    Gracias.

    miércoles, 26 de noviembre de 2014 11:02
  • en mi caso es cdo se da de alta una persona en el sistema se guarda en la tabla y luego se ejecutaria el sp. casi siempre es una fila. Puede ser el caso que hay dos alta  a la misma fechahora

    No, si hubiera dos a la misma hora no habría problema siempre que se inserten con dos sentencias INSERT separadas. Cada una de las dos INSERTS dispararía el trigger, y en cada una de las dos veces al trigger le llegaría la pseudo-tabla INSERTED con un único registro.

    El problema ocurriría si insertases varios registros con una única sentencia (puede ser un "insert into tabla(...) values (...),(...)" o un "insert into tabla select columnas from otratabla"). En ese caso sólo se dispararía el trigger una única vez y le llegarían varios registros en la tabla INSERTED. Si quieres ejecutar el SP para cada uno de esos registros, entonces es cuando el cursor se vuelve necesario.

    Si sabes con toda seguridad que tu programa cliente nunca va a insertar más de un registro con un único INSERT, entonces puedes presumir que la tabla INSERTED nunca traerá más de un registro y se puede eliminar el cursor. Pero es una pequeña chapuza; si alguna vez se modifica el código cliente, o se hace alguna operación de mantenimiento que importe varios registros de golpe, el trigger tendrá un comportamiento inadecuado.

    • Marcado como respuesta sebastian viga miércoles, 26 de noviembre de 2014 21:52
    miércoles, 26 de noviembre de 2014 11:14
  •             Buenos dias Sebastian

                          Te paso un ejemplo para realizar el trigger

    createTRIGGER [dbo].[TI_Barrios] ON [dbo].[FacturaFecha]
    WITH EXECUTE AS CALLER
    FOR INSERT
    AS
    BEGIN

           declare @Fecha datetime;

           select @fecha=fecha from inserted;    

           sp_procedimiento(@fecha);
    END

    Saludos

    BEMO

    Paraguay

    • Marcado como respuesta sebastian viga miércoles, 26 de noviembre de 2014 21:52
    miércoles, 26 de noviembre de 2014 12:08
  • >>

     En conclusión: recomiendo dejar el cursor tal como está en el ejemplo de Jesús. La mayor parte de las veces hará una única iteración, y no merece la pena incurrir en el aumento de complejidad en el mantenimiento del código que se ocasionaría para eliminarlo, a cambio de una minúscula ganancia en eficiencia.

    <<

    Estoy bastante de acuerdo con lo que dice Alberto, en realidad, deshacerse del cursor sólo merecería la pena si se insertaran bastantes registros en una sóla instrucción, y eso suele ser poco habitual.

    Pero ya puestos, podríamos eliminar el cursor haciendo una pequeña optimización para cuando sólo se inserte una fila:

    CREATE TRIGGER MiTrigger 
    ON Orders FOR INSERT
    AS
            DECLARE @RowCount int
            SET @RowCount = @@ROWCOUNT
    	IF @RowCount = 0 RETURN
    	SET NOCOUNT ON
    
            DECLARE @OrderDate datetime
            
            IF @RowCount = 1
            BEGIN
                 SELECT @OrderDate = OrderDate
                 FROM inserted
                 EXEC MiProc @OrderDate
                 RETURN
            END
    
    
    	DECLARE c CURSOR LOCAL
    	FOR SELECT OrderDate
    	FROM inserted
    	OPEN c
    	
    	
    	FETCH NEXT FROM c INTO @OrderDate
    	WHILE @@FETCH_STATUS = 0
    	BEGIN
    		EXEC MiProc @OrderDate
    		FETCH NEXT FROM c INTO @OrderDate
    	END
    	CLOSE c
    	DEALLOCATE c
    	
    GO



    Jesús López


    EntityLite a lightweight, database first, micro orm

    • Marcado como respuesta sebastian viga miércoles, 26 de noviembre de 2014 21:52
    miércoles, 26 de noviembre de 2014 17:54
  • >>

    jesus no  entendi porque el cursor , pero porque hace rato no toco sql server . Por cada fila no se ejecutaria el trigger. 

    <<

    Los triggers no se ejecutan por cada fila, se ejecutan por cada instrucción y una instrucción como por ejemplo una del tipo INSERT INTO MiTabla(<lista de campos>) SELECT <lista de campos> FROM ... inserta más de un registro en la tabla, entonces, dentro del trigger tienes todos los registros insertados por la instrucción en la tabla virtual inserted. Por eso lo del cursor, porque hay que ejecutar el procedimiento por cada fila insertada, o sea, por cada fila en la tabla inserted, y la única manera de ejecutar un procedimiento por cada fila en una tabla es usando un cursor. Aunque, como he dicho antes, se podría incluir la lógica del procedimiento en el trigger, pero modificándola para que funcionara para más de una fecha: todas las fechas en la tabla inserted.




    Jesús López


    EntityLite a lightweight, database first, micro orm


    • Editado Jesús López miércoles, 26 de noviembre de 2014 18:01 x
    • Marcado como respuesta sebastian viga miércoles, 26 de noviembre de 2014 21:48
    miércoles, 26 de noviembre de 2014 18:00
  • perdon la demora recien llego del trabajo y no pude acceder .

    Jesús Lópezuse tu solucion 

    Gracias  a todos , genios 

    miércoles, 26 de noviembre de 2014 21:49