一些笔记...
我可以肯定地保证不会有满足条件的行
FROM video_ratings
WHERE RATINGS='0'
AND RATINGS='1'
AND RATINGS='2'
考虑一下。如果其中一个条件(比较)评估为 TRUE,则其他比较将评估为 FALSE,并且
TRUE AND FALSE AND FALSE
将评估为 FALSE。
因此,该语句上的 COUNT() 聚合将评估为 0。
在这个 UPDATE 语句中,
update video_upload set RATE=TOTAL;
成功了,这将更新 video_upload 表中的每一行。似乎我们只想更新 video_upload 表上的 一个 行,该行的 ID 值与我们刚刚插入到 videos_ratings 表中的行的 VID_ID 匹配。
我们可以通过引用得到我们刚刚插入的行的VID_ID列的值
NEW.VID_ID
在触发器主体中。我们可能想要一个如下所示的更新语句:
UPDATE video_upload v
SET ...
WHERE v.ID = NEW.VID_ID ;
如果我们想为RATE_BAD、RATE_AVERAGE、RATE_GOOD 和RATE_BEST 列赋值,我们需要 SET 子句来引用这些列...
UPDATE video_upload v
SET v.RATE_BAD = some_expr
, v.RATE_AVERAGE = another_expr
, v.RATE_GOOD = expr_for_good
, v.RATE_BEST = expr_for_best
WHERE v.ID = NEW.VID_ID ;
也许我们想做这样的事情,以获取评分计数并将这些计数存储在局部变量中,以便我们稍后可以在触发器中引用这些计数。
SELECT IFNULL(SUM(r.RATINGS='0'),0) AS cnt_r0
, IFNULL(SUM(r.RATINGS='1'),0) AS cnt_r1
, IFNULL(SUM(r.RATINGS='2'),0) AS cnt_r2
, IFNULL(SUM(r.RATINGS='3'),0) AS cnt_r3
FROM video_ratings r
WHERE r.VID_ID = NEW.VID_ID
INTO li_cnt_r0
, li_cnt_r1
, li_cnt_r2
, li_cnt_r3
;
跟进
我推荐这种模式用于触发器名称:table_name + _suffix
其中_suffix 是“_ad”、“_ai”、“_au”、“_bd”、“_bi”、“_bu”之一(用于删除/插入/更新之后/之前)
遵循这个命名约定可以避免命名冲突,当我们在表上查找触发器时,我们会知道在哪里找到它们。通过按字母顺序列出触发器,给定表的所有触发器将按 table_name (大部分)分组在一起。 (在极端情况下,我们可能会进行一些混合,即表名以另一个表的名称开头,后跟 _a.. 或 _b..)
(在早期开发中,当您有两个表和六个触发器时,这种命名约定的优势并不明显。但是当数据库包含大量表和触发器时,它变得很明显。)
另请注意,对于给定表上的每个 BEFORE/AFTER INSERT/UPDATE/DELETE,MySQL 仅支持单个触发器。
使用局部变量而不是用户定义的变量,除非有特定原因需要使用用户定义的变量。
DELIMITER $$
DROP TRIGGER IF EXISTS video_ratings_ad$$
CREATE TRIGGER video_ratings_ad
AFTER DELETE ON video_ratings
FOR EACH ROW
BEGIN
-- declare local variables
DECLARE li_cnt_r0 BIGINT;
DECLARE li_cnt_r1 BIGINT;
DECLARE li_cnt_r2 BIGINT;
DECLARE li_cnt_r3 BIGINT;
-- get counts of ratings for specific VID_ID
-- and store counts in local variables
SELECT IFNULL(SUM(r.RATINGS='0'),0) AS cnt_r0
, IFNULL(SUM(r.RATINGS='1'),0) AS cnt_r1
, IFNULL(SUM(r.RATINGS='2'),0) AS cnt_r2
, IFNULL(SUM(r.RATINGS='3'),0) AS cnt_r3
FROM video_ratings r
WHERE r.VID_ID = OLD.VID_ID
INTO li_cnt_r0
, li_cnt_r1
, li_cnt_r2
, li_cnt_r3
;
-- update target table with rating counts from local variables
UPDATE video_upload t
SET t.RATE_BAD = li_cnt_r0
, v.RATE_AVERAGE = li_cnt_r1
, v.RATE_GOOD = li_cnt_r2
, v.RATE_BEST = li_cnt_r3
WHERE t.ID = OLD.VID_ID
;
END$$
DROP TRIGGER IF EXISTS video_ratings_ai$$
CREATE TRIGGER video_ratings_ai
AFTER UPDATE ON video_ratings
FOR EACH ROW
BEGIN
-- declare local variables
DECLARE li_cnt_r0 BIGINT;
DECLARE li_cnt_r1 BIGINT;
DECLARE li_cnt_r2 BIGINT;
DECLARE li_cnt_r3 BIGINT;
-- get counts of ratings for specific VID_ID
-- and store counts in local variables
SELECT IFNULL(SUM(r.RATINGS='0'),0) AS cnt_r0
, IFNULL(SUM(r.RATINGS='1'),0) AS cnt_r1
, IFNULL(SUM(r.RATINGS='2'),0) AS cnt_r2
, IFNULL(SUM(r.RATINGS='3'),0) AS cnt_r3
FROM video_ratings r
WHERE r.VID_ID = NEW.VID_ID
INTO li_cnt_r0
, li_cnt_r1
, li_cnt_r2
, li_cnt_r3
;
-- update target table with rating counts from local variables
UPDATE video_upload t
SET t.RATE_BAD = li_cnt_r0
, v.RATE_AVERAGE = li_cnt_r1
, v.RATE_GOOD = li_cnt_r2
, v.RATE_BEST = li_cnt_r3
WHERE t.ID = NEW.VID_ID
;
END$$
DROP TRIGGER IF EXISTS video_ratings_au$$
CREATE TRIGGER video_ratings_au
AFTER UPDATE ON video_ratings
FOR EACH ROW
BEGIN
-- declare local variables
DECLARE li_cnt_r0 BIGINT;
DECLARE li_cnt_r1 BIGINT;
DECLARE li_cnt_r2 BIGINT;
DECLARE li_cnt_r3 BIGINT;
IF( OLD.RATINGS <=> NEW.RATINGS
-- if VID_ID and RATINGS is not changed, we can skip getting counts
IF( NEW.VID_ID <=> OLD.VID_ID AND NEW.RATINGS <=> OLD.RATINGS )
THEN BEGIN END
ELSE
-- get counts of ratings for OLD.VID_ID
-- and store counts in local variables
SELECT IFNULL(SUM(r.RATINGS='0'),0) AS cnt_r0
, IFNULL(SUM(r.RATINGS='1'),0) AS cnt_r1
, IFNULL(SUM(r.RATINGS='2'),0) AS cnt_r2
, IFNULL(SUM(r.RATINGS='3'),0) AS cnt_r3
FROM video_ratings r
WHERE r.VID_ID = OLD.VID_ID
INTO li_cnt_r0
, li_cnt_r1
, li_cnt_r2
, li_cnt_r3
;
-- update target table with rating counts from local variables
UPDATE video_upload t
SET t.RATE_BAD = li_cnt_r0
, v.RATE_AVERAGE = li_cnt_r1
, v.RATE_GOOD = li_cnt_r2
, v.RATE_BEST = li_cnt_r3
WHERE t.ID = OLD.VID_ID
;
IF( NEW.VID_ID <=> OLD.VID_ID )
THEN BEGIN END
ELSE
-- get counts of ratings for specific VID_ID
-- and store counts in local variables
SELECT IFNULL(SUM(r.RATINGS='0'),0) AS cnt_r0
, IFNULL(SUM(r.RATINGS='1'),0) AS cnt_r1
, IFNULL(SUM(r.RATINGS='2'),0) AS cnt_r2
, IFNULL(SUM(r.RATINGS='3'),0) AS cnt_r3
FROM video_ratings r
WHERE r.VID_ID = NEW.VID_ID
INTO li_cnt_r0
, li_cnt_r1
, li_cnt_r2
, li_cnt_r3
;
-- update target table with rating counts from local variables
UPDATE video_upload t
SET t.RATE_BAD = li_cnt_r0
, v.RATE_AVERAGE = li_cnt_r1
, v.RATE_GOOD = li_cnt_r2
, v.RATE_BEST = li_cnt_r3
WHERE t.ID = NEW.VID_ID
;
END IF;
END IF;
END$$
DELIMITER ;