提问人:Finn Kimbrel 提问时间:11/8/2023 最后编辑:marc_sFinn Kimbrel 更新时间:11/9/2023 访问量:27
如何在 SQL 触发器中泛化“WHERE”子句
How to generalize a "WHERE" clause in a SQL trigger
问:
我对 SQL 非常陌生,现在正在练习创建触发器函数。目前,我正在尝试创建一个存储过程,以便在发生销售或库存更新时更新产品记录。现在,它看起来像这样:
CREATE TRIGGER IF NOT EXISTS after_sale_insert
AFTER insert ON sales
BEGIN
INSERT INTO log_messages (message)
VALUES ('new sale record created and product quantity updated');
UPDATE products
SET quantity = (SELECT products.quantity - sales.quantity_sold
FROM products
JOIN sales ON products.product_id = sales.product_id)
WHERE products.product_id = sales.product_id;
END;
触发器在“WHERE”元素之前工作正常,我尝试使用它来指定表中的产品 ID 应与触发命令 () 输入的产品 ID 匹配。Products
products.product_id = [whatever product_id is inserted into "Sales"]
我正在使用以下命令对其进行测试:
INSERT INTO sales (product_id, quantity_sold)
VALUES (1, 20);
但是,我现在拥有它的方式只是使我的程序(SQLite)返回错误(“没有这样的列:sales.product_id”)。总而言之:我正在努力弄清楚如何创建一个可以普遍适用并且仍然可以在SQLite中起作用的子句。有什么帮助吗?WHERE
我的表的完整代码如下:
CREATE TABLE products
(
product_id INTEGER PRIMARY KEY,
product_name TEXT NOT NULL,
quantity INTEGER NOT NULL,
price REAL NOT NULL
);
CREATE TABLE sales
(
sale_id INTEGER PRIMARY KEY,
product_id INTEGER NOT NULL,
quantity_sold INTEGER NOT NULL,
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
CREATE TABLE stock_updates
(
update_id INTEGER PRIMARY KEY,
product_id INTEGER NOT NULL,
new_quantity INTEGER NOT NULL,
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
CREATE TABLE log_messages
(
id INTEGER PRIMARY KEY,
message TEXT
);
INSERT INTO products (product_name, quantity, price)
VALUES ('Product A', 100, 50.00),
('Product B', 50, 70.00),
('Product C', 200, 30.00);
我尝试过弄乱 JOIN 元素并在语句的各个部分添加“old.”前缀,但这无济于事。如果我删除“WHERE”语句,则触发器在技术上是有效的(因为它不会返回错误),但它将所有产品的数量更改为 20。这是我的测试命令插入到 Sales 表中的数量,但绝对不是它应该做的。
完全删除“WHERE”语句并将“SET”语句更改为“SET quantity = (products.quantity - sales.quantity_sold) FROM products JOIN sales ON products.product_id = sales.product_id”后,我收到错误“模棱两可的列名:products.quantity”。这很令人兴奋,但也不是我正在寻找的解决方案。
答:
看起来 Sqlite 需要您使用特殊的 New
表:
WHEN 子句和触发器操作都可以使用“NEW.column-name”和“OLD.column-name”形式的引用访问正在插入、删除或更新的行的元素
请注意,某些数据库不保证在每次单独的更改时触发触发器,而是可能会将多个事件批处理在一起以提高性能。因此,假设触发器中只有一行,请小心。
此外,在大多数平台上,触发器不能保证是原子的,并且带有“main”语句,因此您必须注意不要设置竞争条件。通常最好在事务中使用两个单独的连续语句来执行此类操作。
评论