SQL 触发列更新顺序

问题描述 投票:0回答:1

这是我删除评论时的触发器,

DELIMITER $$
CREATE TRIGGER after_review_delete
AFTER DELETE ON product_reviews
FOR EACH ROW
BEGIN 
    UPDATE product
    SET
             reviews_count = CASE WHEN OLD.status = 1 
                  THEN reviews_count-1 
                  ELSE reviews_count 
                  END,
      rating = CASE WHEN OLD.status = 1
            THEN CASE
                    WHEN reviews_count = 0 THEN 0 
                    ELSE (rating*(reviews_count+1)+OLD.rating)/reviews_count
               END
            ELSE rating
    WHERE id = OLD.pid;
END$$
DELIMITER ;

这里是查询的一些解释,它是做什么的,它检查

case
是否审核
status = 1
然后这意味着它是一个活跃的审核而不是待定的审核,在它变得活跃之前评级和添加并不重要。

我想问的是该评级或

reviws_count
计算是否准确,因为
rating
列值是相关的或
reviews_count
以及在计算评级期间我是否会得到
reviews_count
初始值或值已更新。

我也可以这样做,但它会再次选择产品,我的应用程序逻辑已经这样做了,感觉有点慢,

DELIMITER $$

CREATE TRIGGER after_review_delete
AFTER DELETE ON product_reviews
FOR EACH ROW
BEGIN
    -- Declare local variables to hold current values
    DECLARE current_reviews_count INT;
    DECLARE current_rating DECIMAL(10, 2);

    -- Fetch the current reviews count and rating
    SELECT reviews_count, rating INTO current_reviews_count, current_rating
    FROM product
    WHERE id = OLD.pid;

    -- Update the product table with conditional logic
    UPDATE product
    SET
        reviews_count = CASE
                           WHEN OLD.status = 1 THEN current_reviews_count - 1
                           ELSE current_reviews_count
                        END,
        rating = CASE
                    WHEN OLD.status = 1 THEN
                        CASE
                            WHEN current_reviews_count - 1 = 0 THEN 0 -- No reviews left
                            ELSE (current_rating * current_reviews_count - OLD.rating) / (current_reviews_count - 1)
                        END
                    ELSE current_rating
                 END
    WHERE id = OLD.pid;
END$$

DELIMITER ;

我想要最准确和最快的解决方案,我的第一种方法是否正确,我可以安全地避免第二种方法吗?

我已经检查了这个答案,但没有要求触发器。

这是我的服务器版本以及操作系统信息。 Mysql 版本 8.0.39-0 ubuntu0.24.04.1 适用于 x86_64 上的 Linux ((Ubuntu))

sql mysql mysqli triggers sql-update
1个回答
0
投票

你的第一种方法似乎是正确的,但是SQL中的操作顺序以及如何使用reviews_count来计算新评级存在问题。

SQL 不保证 UPDATE 语句中表达式的求值顺序。这意味着评级计算中使用的reviews_count值可能不会反映在同一UPDATE操作期间(在减少之后)更新的值。因此,这可能会导致错误的结果。

如果 OLD.status = 1,reviews_count 减 1。 然后,在同一个 UPDATE 语句中,您将使用 Reviews_count 可能仍为原始值来计算新评级。鉴于在评分计算过程中reviews_count可能尚未减少,因此计算可能基于原始reviews_count,从而导致评分不正确。

第二种方法更安全:

由于您在进行计算之前显式获取值,因此您可以确保计算中使用的值是正确且最新的。

此方法避免了 SQL UPDATE 语句中操作顺序的潜在陷阱。


如果你问我,我会建议优化第二种方法。以下是一些简单的步骤;

  • Indexes:确保Product表中的id列是 已编入索引。这将加快 SELECT 和 UPDATE 操作的速度。
  • 最小化延迟:如果可能,您可以优化您的应用程序 减少不必要的查询逻辑,但是非常重要 优先考虑触发器本身的正确性。

第二种方法更可靠,可以确保正确计算reviews_count和 rating。尽管它需要额外的 SELECT,但所获得的准确性通常值得权衡。

© www.soinside.com 2019 - 2024. All rights reserved.