MySQL 仅在条件为真时更新主字段

Posted

技术标签:

【中文标题】MySQL 仅在条件为真时更新主字段【英文标题】:MySQL update a master field only if condition is true 【发布时间】:2021-11-15 23:02:54 【问题描述】:

有没有办法以这种方式更新SQL,例如。

主表有一个名为 INVOICESCOUNT 的列。

成功删除发票后,INVOICESCOUNT 会减少。

例如,这样的 SQL 伪代码语句:

Delete From Invoices where INVOICE=500;
Update Customers SET INVOICECOUNT=INVOICECOUNT-1 WHERE Customer=1  (if prior statement returns 1 affected row);

我需要将它嵌入到同一个 SQL 语句中,而不是让源代码处理分别执行 2 个语句。

感谢您的任何建议。如果有这样的解决方案,也请告诉我是否有最低 mysql 版本要求。

更新更多信息:请注意,我向用户展示的客户列表每次都可能非常不同,例如 CustomerGroupID=?或 CustomerCreated 在特定日期内,因此无法有效缓存客户查询,因此我更喜欢更新 INVOICECOUNT(因为列出不同客户组的不同用户会在一小时内多次点击它)。

【问题讨论】:

您不需要表格来记录您的计数。 SQL可以帮你算 您不应该将 派生数据 存储在 RDBMS 的表中,包括“另一个表中满足某些条件的行数”之类的聚合 - 而是使用 VIEW .有许多 原因不存储这样的派生数据,即因为它过时 并且变得不正确。数据库的设计应使它们永远不会包含可能过时的内部派生数据。 【参考方案1】:

更好的主意:改为使用 VIEW 来显示客户的发票数量:

CREATE VIEW CustomersInfo AS

SELECT
    CustomerId,
    COUNT(*) AS InvoiceCount
FROM
    Invoices
GROUP BY
    CustomerId
;

然后你会像这样使用它:

SELECT
    c.CustomerId,
    COALESCE( ci.InvoiceCount, 0 ) AS InvoiceCount
FROM
    Customers AS c
    LEFT OUTER JOIN CustomersInfo AS ci ON c.CustomerId = ci.CustomerId

(不要使用INNER JOIN,否则没有任何发票的客户将不会在输出中)。

【讨论】:

感谢您提供的替代方法。此示例对于其他一些基于客户端的 sql 代码可能很有用。也许我给出的例子不是最好的,因为我们的场景更复杂。但由于性能原因的一些内部原因,每次出现这样的“查询发票计数”时,我都无法计算发票。有没有办法像我原来的问题一样执行条件 SQL 语句? @PeterJones 性能不是借口:MySQL supports cached materialized views。如果您的原始问题不能代表您的实际问题,那么您应该编辑您的问题帖子以描述您的实际问题 请参阅“更新更多信息”,我每次都需要列出非常不同的客户组,因此缓存可能无法正常工作。我很抱歉没有提到这一点。您的 View 示例是一个好主意,我可以在其他场景中使用它。感谢您的样品。非常感激。我赞成你的回答。【参考方案2】:

您可以为此使用触发器

CREATE TABLE Invoices(INVOICE INT)
CREATE TABLe Customers(Customer int,INVOICECOUNT int)
INSERT INTO Customers VALUES (1,1)
CREATE TRIGGER del_after AFTER DELETE ON Invoices
FOR EACH ROW
Update Customers SET INVOICECOUNT=INVOICECOUNT-1 WHERE Customer=1 
Delete From Invoices where INVOICE=500;
SELECT * FROM Customers
客户 |发票计数 --------: | ------------: 1 | 1
INSERT INTO Invoices VALUES (400)
Delete From Invoices where INVOICE=500;
SELECT * FROM Customers
客户 |发票计数 --------: | ------------: 1 | 1
INSERT INTO Invoices VALUES (500)
Delete From Invoices where INVOICE=500;
SELECT * FROM Customers
客户 |发票计数 --------: | ------------: 1 | 0

db小提琴here

【讨论】:

感谢您的指点。我赞成这个答案。看起来 MySQL 有很多选择。【参考方案3】:

正如 cmets 中提到的,您可能不需要将发票计数存储在表格列中,但是如果您出于任何原因必须拥有发票计数列,则最好的选择可能是存储过程。

DELIMITER //
CREATE PROCEDURE removeinvoice
BEGIN
    DELETE FROM invoices WHERE invoice=500;
    UPDATE customers SET invoicecount = (SELECT COUNT(*) FROM invoices);
END//
DELIMITER ;

然后你只需调用那个存储过程。

CALL removeinvoice;

【讨论】:

以上是关于MySQL 仅在条件为真时更新主字段的主要内容,如果未能解决你的问题,请参考以下文章

仅在条件为真时添加指令 [重复]

基本布尔逻辑——如何仅在另一个条件为真时测试条件

Javascript:<script src=jquery...仅当条件为真时

如何执行?当某些条件为真时,带有 OR 的 jquery.on 事件?

当某个命令为真时,如何更新 python pygame 中的文本?

C while 循环仅在语句为真时运行?