如何优化此触发器?效果很好,但我认为可以改进:
CREATE TRIGGER `update_request_missions_after_insert` BEFORE INSERT ON `request_missions`
FOR EACH ROW
IF ((SELECT id FROM request_missions ORDER BY id DESC LIMIT 1)+1) >= 1 AND
((SELECT id FROM request_missions ORDER BY id DESC LIMIT 1)+1) <= 9 THEN
SET New.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%y'), '-',
CONCAT('00000',(SELECT id FROM request_missions ORDER BY id DESC LIMIT 1)+1));
END IF
结果将在rm_number
列中,例如:
id> = 1和id <= 9
19-000001
19-000002
...
19-000009
答案 0 :(得分:0)
这里建议使用局部变量,而不要重复三次子查询。你说那是你的担心。
CREATE TRIGGER `update_request_missions_after_insert` BEFORE INSERT ON `request_missions`
FOR EACH ROW
BEGIN
DECLARE next_id INT;
SELECT COALESCE(MAX(id),0) + 1 INTO next_id FROM request_missions;
IF next_id BETWEEN 1 AND 9 THEN
SET NEW.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%y'), '-', '00000', next_id);
END IF;
END
警告:这会遇到比赛条件。例如,如果两个会话同时插入到表中,则它们可能都读取相同的next_id
。
同样,如@ P.Salmon所述,如果next_id
为> 9,则结果不确定。我不确定您要做什么。
您可能希望允许更长的数字,并使用零填充它们到固定长度:
LPAD(next_id, 6, '0')
有关LPAD()功能的信息,请参见手册。
如果表有零行,我使用COALESCE(MAX(id),0)
来确保至少返回一个非NULL值。
这也涉及到:
DATE_FORMAT(CURDATE(),'%y')
两位数的年份将在81年内累积到00
。这正是Y2K问题的产生原因!我知道您届时将不会使用该代码,因此您可能不在乎。但是您应该始终编写代码,就像最终维护您的代码的人是知道您的住所的暴力精神病患者一样。
将您的新代码重新发布到另一个答案中
这是一个更好的解决方案,用于处理最大为999,999的next_id数字。
CREATE TRIGGER `update_request_missions_after_insert` BEFORE INSERT ON `request_missions`
FOR EACH ROW
BEGIN
DECLARE next_id INT;
SELECT COALESCE(MAX(id),0) + 1 INTO next_id FROM request_missions;
IF next_id < 1000000 THEN
SET NEW.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%y'), '-', LPAD(next_id, 6, '0'));
ELSE
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'RM Number has reached capacity'
END IF;
END
种族条件问题有所不同,使用MAX(id)
查找最后一个ID时没有解决方案。问题是您可能有多个客户端同时插入到表中。每个客户的会话将为MAX(id)
读取相同的值并使用它。
您应该阅读有关Race Conditions的信息。
您真正需要的是某种使用AUTO_INCREMENT
值的方式,该值以线程安全的方式生成新的唯一值,并将该值复制到您的rm_number
中。
不幸的是,无法在触发器中执行此操作。在INSERT触发器之前,尚未生成新的AUTO_INCREMENT值。在AFTER INSERT触发器期间,您无法修改NEW.rm_number
,因为插入已经完成。我过去曾写过这本书:
答案 1 :(得分:0)
感谢M. Bill Karwin,现在代码更清晰了 对于一年级的问题,我将其更改为'%Y'。 现在的代码是:
CREATE TRIGGER `update_request_missions_after_insert` BEFORE INSERT ON `request_missions`
FOR EACH ROW
BEGIN
DECLARE next_id INT;
SELECT COALESCE(MAX(id),0) + 1 INTO next_id FROM request_missions;
IF next_id BETWEEN 1 AND 9 THEN
SET NEW.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%Y'), '-', '00000', next_id);
ELSEIF next_id BETWEEN 10 AND 99 THEN
SET NEW.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%Y'), '-', '0000', next_id);
ELSEIF next_id BETWEEN 100 AND 999 THEN
SET NEW.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%Y'), '-', '000', next_id);
ELSEIF next_id BETWEEN 1000 AND 9999 THEN
SET NEW.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%Y'), '-', '00', next_id);
ELSEIF next_id BETWEEN 10000 AND 99999 THEN
SET NEW.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%Y'), '-', '0', next_id);
ELSEIF next_id BETWEEN 100000 AND 999999 THEN
SET NEW.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%Y'), '-', next_id);
END IF;
END
警告:这会遇到比赛条件。例如,如果两个 会话同时插入到表中,它们可能都 读取相同的next_id。
知道此触发器的目的是为添加的每行添加一个格式为“ YYYY-ID”的数字吗? YYYY:是当前年份 ID:是当前行的ID,格式如触发器中所示