我正在创建一个 MySQL 数据库。我有两个不同的表:用于销售(
id, idoftheproduct, quantity
)和用于供应(id, idoftheproduct, quantity
)。我想要一个触发器,每当我们添加新的销售或新的供应时,它都会增加或减少称为 Stock(idoftheproduct, quantity
) 的不同表的值
简而言之,不要。相反,创建一个视图:
CREATE VIEW Stock
AS
SELECT IDofTheProduct, SUM(Quantity) AS Quantity
FROM ( SELECT IDofTheProduct, Quantity
FROM Supplies
UNION ALL
SELECT IdOfTheProduct, -Quantity
FROM Sales
) t
GROUP BY IDofTheProduct;
这样,无论您的基础表发生变化,您的视图都会发生变化。这在更新/插入期间的开销较小,并且始终准确,即使触发器由于某种原因没有触发。
编辑
抱歉,我忘记了 MySQL 不允许在视图中使用子查询。一种解决方案是创建一个新视图来代替子查询:
CREATE VIEW SalesAndSupplies
AS
SELECT 'Supplies' AS `Type`,
IDofTheProduct,
Quantity
FROM Supplies
UNION ALL
SELECT 'Sales' AS `Type`,
IDofTheProduct,
-Quantity
FROM Sales;
CREATE VIEW Stock
AS
SELECT IDofTheProduct, SUM(Quantity) AS Quantity
FROM SalesAndSupplies
GROUP BY IDofTheProduct;
带有视图的解决方案是一个很好的解决方案,但随着时间的推移,它往往会变得更慢,特别是如果您有大量销售和供应数据,因为您总是计算它。
因此,如果您决定通过触发器来实现它,那么您必须至少有四个触发器(在两个表上插入和删除)。由于它们都更新了库存,因此最好将部分代码分解为存储过程。
更新库存的存储过程
CREATE PROCEDURE sp_update_stock(IN pid INT, IN qty DECIMAL(11, 3))
INSERT INTO stock (idoftheproduct, quantity)
VALUES (pid, qty)
ON DUPLICATE KEY UPDATE quantity = quantity + qty;
如果执行时不存在带有
idoftheproduct
的行,则会创建该行。否则,它将更新以反映更改。
现在触发
CREATE TRIGGER tg_sales_insert
AFTER INSERT ON sales
FOR EACH ROW
CALL sp_update_stock(NEW.idoftheproduct, -1 * NEW.quantity);
CREATE TRIGGER tg_supplies_insert
AFTER INSERT ON supplies
FOR EACH ROW
CALL sp_update_stock(NEW.idoftheproduct, NEW.quantity);
CREATE TRIGGER tg_sales_delete
AFTER DELETE ON sales
FOR EACH ROW
CALL sp_update_stock(OLD.idoftheproduct, OLD.quantity);
CREATE TRIGGER tg_supplies_delete
AFTER DELETE ON supplies
FOR EACH ROW
CALL sp_update_stock(OLD.idoftheproduct, -1 * OLD.quantity);
现在您可以在销售和供应中插入和删除。
INSERT INTO Supplies VALUES (NULL, 1, 100), (NULL, 1, 50), (NULL, 1, 75);
INSERT INTO Sales VALUES (NULL, 1, 2),(NULL, 1, 10), (NULL, 1, 5);
DELETE FROM Sales WHERE id = 1;
DELETE FROM Supplies WHERE id = 3;
如果看一下
stock
就会看到
|产品的IDO数量 | ---------------------------- | 1 | 135 | 135
这里是SQLFiddle演示
我和你有同样的情况,如果我要创建一个供应商,销售,detail_stock和detail_supplier表,那么前面有名称detail的表将包含主键列,外键来自商品和供应商表,供应商发货金额(针对供应商发货明细),采购金额(针对采购表),最后是采购状态或供应商发货状态(这里我每个明细都使用两种状态)。我使用此状态来触发我作为下面的查询创建的触发器。
-- TRIGGER
DELIMITER /
CREATE TRIGGER trigger_update_purchase
AFTER INSERT ON detail_status_transaction
FOR EACH ROW
BEGIN
DECLARE quantity_of_items_purchased INT;
SET quantity_of_items_purchased = NEW.quantity_purchased;
IF NEW.status_transaction = 'Completed' THEN
-- Update stock_book
UPDATE book
SET stock_book = stock_book - quantity_of_items_purchased
WHERE book_id = (SELECT book_id FROM transaction WHERE id_nota = NEW.transaction_id);
elseif NEW.transaction_status = 'Refund' then
update book
set stock_book = stock_book + quantity_of_items_purchased
where id_book = (select book_id from transaction where id_nota = NEW.transaction_id);
END IF;
END;
DELIMITER ;
触发更新供应商
DELIMITER /
CREATE TRIGGER trigger_update_supplier
AFTER INSERT ON detail_status_supplier
FOR EACH ROW
BEGIN
DECLARE quantity_buy_items INT;
SET quantity_buy_items= NEW.quantity_shipped;
IF NEW.status_supplier = 'Success' THEN
-- Update book stock (supplier)
UPDATE book
SET stock_book = stock_book + quantity_buy_items
WHERE id_book = (SELECT id_book FROM book WHERE id_book = NEW.book_id);
elseif NEW.status_supplier = 'Failed' then
update book
set stock_book = stock_book - quantity_buy_items
where id_book = (SELECT id_book FROM book WHERE id_book = NEW.book_id);
END IF;
END;
DELIMITER ;
然后通过在details表中输入输入来触发此触发器,将使库存根据触发的内容和所需的条件减少或增加。