none
Duda Trigger devolver stock RRS feed

  • Pregunta

  • Buenas tardas compañeros espero me pueda ayudar, lo que trato de hacer es un trigger en el cual al borrar una venta,me regrese al stock la cantidad de articulos que tenia dicha venta, ya logre agruparlos por articulo y cantidad de cada uno, lo que no se es como poder guardarlo en variables para poder hacer el update en el campo stock de los articulos.

    Este es el codigo que uso para obtener la cantidad y agruparlos por articulo

    select sum(D.CANTIDAD) as CANTIDAD, D.FK_COD_BARRA 
    	FROM VENTAS_ZAPATOS D
    	WHERE D.FK_ID_VENTA='1090'
    	group by D.FK_COD_BARRA

    entonces si por ejemplo tengo 3 productos en una misma venta como le hago para que al borrarla, regrese el stock a cada producto?

    Muchas gracias por la atencion

    domingo, 9 de septiembre de 2018 5:05

Respuestas

  • No, no puedes hacerlo declarando una variable escalar y metiendo en ella toda la suma de todo lo que se ha borrado, porque se podrían haber borrado distintos artículos y de esta manera sacarías la suma total, no la suma de cada artículo.

    Olvídate del "SUM". No hay que sumar nada. En las líneas que se borran ya está la cantidad que se ha borrado. Esa cantidad la restas del stock de ese mismo artículo. Por lo tanto basta con un delete de Stock from Deleted, ya que en el deleted viene el código del artículo y viene la cantidad que se borró de ese artículo. No importa si el mismo artículo existe en varias líneas, el update restará todas las cantidades de todas las líneas, no hay que sumarlas de antemano.

    domingo, 9 de septiembre de 2018 17:35
  • Que tal buenas noches, primeramente muchas gracias por ayudarme, este es el trigger final

    USE [ZAPATERIAFINAL]
    GO
    /****** Object:  Trigger [dbo].[BORRARVENTA]    Script Date: 09/09/2018 09:29:58 p. m. ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER TRIGGER [dbo].[BORRARVENTA] ON [dbo].[VENTAS_ZAPATOS]
    AFTER DELETE
    AS
    UPDATE ARTICULOS
        SET STOCK=STOCK+(select D.CANTIDAD FROM DELETED D, ARTICULOS A WHERE A.COD_BARRA=D.FK_COD_BARRA)  
        FROM DELETED D, ARTICULOS A
        WHERE A.COD_BARRA=D.FK_COD_BARRA

    pero me manda este error, cuando se ejecuta el trigger

    Msg 512, Level 16, State 1, Procedure BORRARVENTA, Line 14
    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.

    • Editado pepe1496 lunes, 10 de septiembre de 2018 2:38
    • Marcado como respuesta Pablo RubioModerator miércoles, 12 de septiembre de 2018 16:43
    lunes, 10 de septiembre de 2018 2:37
  • UPDATE ARTICULOS SET STOCK=STOCK+(select D.CANTIDAD FROM DELETED D, ARTICULOS A WHERE A.COD_BARRA=D.FK_COD_BARRA) FROM DELETED D, ARTICULOS A WHERE A.COD_BARRA=D.FK_COD_BARRA

    pero me manda este error, cuando se ejecuta el trigger

    Msg 512, Level 16, State 1, Procedure BORRARVENTA, Line 14
    Subquery returned more than 1 value. [...]

    El error de "Subquery returned more than 1 value" se produce porque la subconsulta devolvió más de un valor (casi seguro debido a que en DELETED hay más de un cod_barra que coincide con el fk_codbarra de Articulos), pero cuando haces SET STOCK=STOCK+algo, ese algo tiene que ser un único número, no puede ser una lista.

    No hay necesidad de hacer una subconsulta, basta con que tomes la cantidad de la consulta principal, y esto funcionará incluso aunque se dé la circunstancia anterior de que haya dos coincidencias, porque el UPDATE sumará las dos:

    UPDATE A
        SET STOCK=STOCK+D.CANTIDAD
        FROM DELETED D
    JOIN ARTICULOS A
        ON A
    .COD_BARRA=D.FK_COD_BARRA

    Te he cambiado la sintaxis antigua de SQL-89 por la más moderna de SQL-92 (usando JOIN y ON en lugar de listar las tablas y usar un WHERE). Aunque en tiempo de ejecución las dos dan lo mismo, con el "ON" resulta más clara la intencionalidad del desarrollador, permitiendo distinguir las condiciones de unión entre tablas de las condiciones de filtro de registros.

    lunes, 10 de septiembre de 2018 5:53

Todas las respuestas

  • Tendrías que meter un trigger "after delete" en la tabla de lineas de detalle de la venta. Presumiblemente, al borrar la venta estás borrando en cascada las líneas de detalle de la misma, por lo que al trigger le llegará en la colección "deleted" toda la lista de líneas que se han borrado. Con esa lista, tendr´s que hacer un update de la tabla de stock. Más o menos en líneas generales la sentencia que tendrías que escribir es la siguiente, pero como es lógico tendrás que adaptarla a tu caso particular poniendo las tablas y campos que realmente correspondan.

    UPDATE A Set A.cantidad = A.cantidad-B.cantidad
    FROM Stock as A
    JOIN DELETED as B on A.CodBarra=B.CodBarra
    

    domingo, 9 de septiembre de 2018 6:37
  • Tengo este trigger pero no me funciona como quiero

    USE [ZAPATERIAFINAL]
    GO
    /****** Object:  Trigger [dbo].[BORRARVENTA]    Script Date: 09/09/2018 10:47:01 a. m. ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER TRIGGER [dbo].[BORRARVENTA] ON [dbo].[VENTAS_ZAPATOS]
    AFTER DELETE
    AS
    	declare @ctn int;
    	SET @ctn=(select sum(D.CANTIDAD) FROM DELETED D, ARTICULOS A WHERE A.COD_BARRA=D.FK_COD_BARRA)  
    	UPDATE ARTICULOS
        SET STOCK=STOCK+@ctn
        FROM DELETED D, ARTICULOS A
        WHERE A.COD_BARRA=D.FK_COD_BARRA

    si la venta que voy a borrar tiene varios articulos me los suma todos y no me los separa por articulo, entonces si tengo 10 articulos A y 10 B, los suma y son 20 y regresa 20 al stock del articulo A y B, en lugar de 10 y 10

    domingo, 9 de septiembre de 2018 15:49
  • No, no puedes hacerlo declarando una variable escalar y metiendo en ella toda la suma de todo lo que se ha borrado, porque se podrían haber borrado distintos artículos y de esta manera sacarías la suma total, no la suma de cada artículo.

    Olvídate del "SUM". No hay que sumar nada. En las líneas que se borran ya está la cantidad que se ha borrado. Esa cantidad la restas del stock de ese mismo artículo. Por lo tanto basta con un delete de Stock from Deleted, ya que en el deleted viene el código del artículo y viene la cantidad que se borró de ese artículo. No importa si el mismo artículo existe en varias líneas, el update restará todas las cantidades de todas las líneas, no hay que sumarlas de antemano.

    domingo, 9 de septiembre de 2018 17:35
  • Que tal buenas noches, primeramente muchas gracias por ayudarme, este es el trigger final

    USE [ZAPATERIAFINAL]
    GO
    /****** Object:  Trigger [dbo].[BORRARVENTA]    Script Date: 09/09/2018 09:29:58 p. m. ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER TRIGGER [dbo].[BORRARVENTA] ON [dbo].[VENTAS_ZAPATOS]
    AFTER DELETE
    AS
    UPDATE ARTICULOS
        SET STOCK=STOCK+(select D.CANTIDAD FROM DELETED D, ARTICULOS A WHERE A.COD_BARRA=D.FK_COD_BARRA)  
        FROM DELETED D, ARTICULOS A
        WHERE A.COD_BARRA=D.FK_COD_BARRA

    pero me manda este error, cuando se ejecuta el trigger

    Msg 512, Level 16, State 1, Procedure BORRARVENTA, Line 14
    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.

    • Editado pepe1496 lunes, 10 de septiembre de 2018 2:38
    • Marcado como respuesta Pablo RubioModerator miércoles, 12 de septiembre de 2018 16:43
    lunes, 10 de septiembre de 2018 2:37
  • Hola pepe1496:

    Tu consulta puede ser tal que así:

    /*creación bbdd Ejemplo*/
    
    CREATE DATABASE zapateria;
    GO
    USE zapateria;
    GO
    
    /*creación tablas Ejemplo*/
    
    CREATE TABLE articulos
    (id        INT,
     stock     FLOAT,
     cod_barra VARCHAR(13)
    );
    GO
    CREATE TABLE venta_zapatos
    (fk_id_venta  INT,
     fk_cod_Barra VARCHAR(13),
     cantidad     FLOAT,
    );
    GO
    
    /*Inserccion de 3 artículos*/
    
    INSERT INTO articulos
    (id,
     stock,
     cod_barra
    )
    VALUES
    (1, 150, '1234'),
    (2, 3223, '2345'),
    (3, 423, '1546');
    GO
    
    /*creacion del disparador*/
    
    CREATE TRIGGER [dbo].[TR_BORRARVENTA] ON [dbo].[VENTA_ZAPATOS]
    AFTER DELETE
    AS
         WITH cte
              AS ( /*realizamos una consulta en una tabla de expresión común para la suma por cod_barra*/
              SELECT SUM(cantidad) AS cantidad,
                     d.fk_cod_Barra
              FROM deleted d
              GROUP BY d.fk_cod_Barra
    		  )/*fin de la tabla de expresión común basada en la pseudo-tabla deleted*/
              UPDATE a /*actualizamos la tabla articulos con el stock que procede de las ventas borradas */
                SET
                    a.STOCK = a.stock - c.cantidad
              FROM articulos a
                   INNER JOIN cte c ON a.cod_barra = c.fk_cod_Barra; /*relación del cte con articulos */
    GO
    /*insertamos ventas para el ejemplo*/
    INSERT INTO venta_zapatos
    (fk_id_venta,
     fk_cod_Barra,
     cantidad
    )
    VALUES
    (1, '1234', 25),
    (2, '1234', 10),
    (3, '2345', 3223),
    (4, '1234', 10),
    (5, '1234', 5);
    GO
    /*borramos 4 filas, 3 de un articulo y 1 de otro */
    DELETE FROM venta_zapatos
    WHERE fk_id_venta IN(1, 2, 3, 5); 
    /*para el articulo 1 hemos borrado las ventas relativas a 40 unidades y para el 2-3223 */
    GO
    SELECT *
    FROM articulos;/*verificamos el correcto funcionamiento del trigger*/
    
     

    Resultado:

    Un saludo

    lunes, 10 de septiembre de 2018 5:38
  • UPDATE ARTICULOS SET STOCK=STOCK+(select D.CANTIDAD FROM DELETED D, ARTICULOS A WHERE A.COD_BARRA=D.FK_COD_BARRA) FROM DELETED D, ARTICULOS A WHERE A.COD_BARRA=D.FK_COD_BARRA

    pero me manda este error, cuando se ejecuta el trigger

    Msg 512, Level 16, State 1, Procedure BORRARVENTA, Line 14
    Subquery returned more than 1 value. [...]

    El error de "Subquery returned more than 1 value" se produce porque la subconsulta devolvió más de un valor (casi seguro debido a que en DELETED hay más de un cod_barra que coincide con el fk_codbarra de Articulos), pero cuando haces SET STOCK=STOCK+algo, ese algo tiene que ser un único número, no puede ser una lista.

    No hay necesidad de hacer una subconsulta, basta con que tomes la cantidad de la consulta principal, y esto funcionará incluso aunque se dé la circunstancia anterior de que haya dos coincidencias, porque el UPDATE sumará las dos:

    UPDATE A
        SET STOCK=STOCK+D.CANTIDAD
        FROM DELETED D
    JOIN ARTICULOS A
        ON A
    .COD_BARRA=D.FK_COD_BARRA

    Te he cambiado la sintaxis antigua de SQL-89 por la más moderna de SQL-92 (usando JOIN y ON en lugar de listar las tablas y usar un WHERE). Aunque en tiempo de ejecución las dos dan lo mismo, con el "ON" resulta más clara la intencionalidad del desarrollador, permitiendo distinguir las condiciones de unión entre tablas de las condiciones de filtro de registros.

    lunes, 10 de septiembre de 2018 5:53
  • Espero que con esta respuesta, despeje todas sus dudas, los disparadores o TRIGGERS no fueron creados para programar la lógica del sistema, en un inicio, cuidaban la DRI (integridad declarativa). Es mejor hacerlo todo por PROCEDIMIENTOS
    lunes, 10 de septiembre de 2018 22:00