Here's a suggestion for using a local variable instead of repeating your subquery three times. You said that was your concern.
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
Warning: this suffers from a race condition. For example, if two sessions are inserting to the table at the same time, they might both read the same next_id
.
Also as @P.Salmon commented above, the results are undefined if next_id
is > 9. I'm not sure what you're trying to do.
You might want to allow longer numbers, and pad them to a fixed length with zeroes:
LPAD(next_id, 6, '0')
See the manual on the LPAD() function.
I used COALESCE(MAX(id),0)
to make sure at least there's one non-NULL value returned, in case the table has zero rows.
This is also concerning:
DATE_FORMAT(CURDATE(),'%y')
A two-digit year will roll over to 00
in 81 years. This is exactly how the Y2K problem was created! I know you won't be working on the code by then, so you might not care. But you should always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.
Re your new code posted in another answer:
This is a better solution for handling the next_id numbers up to 999,999.
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
The race condition issue is different, and there's no solution while you are using MAX(id)
to find the last id. The problem is that you might have more than one client inserting to the table concurrently. Each client's session will read the same value for MAX(id)
and use it.
You should read about Race Conditions.
What you really need is some way of using an AUTO_INCREMENT
value that generates new unique values in a thread-safe manner, and copy the value into your rm_number
.
Unfortunately, there's no way to do this in a trigger. During a BEFORE INSERT trigger, the new AUTO_INCREMENT value is not generated yet. During an AFTER INSERT trigger, you can't modify NEW.rm_number
because the insert is already done. I wrote about this in the past: