Your ID can be thought of a hexadecimal number consisting of letters only, followed by a decimal number. Each hexadecimal digit starts a new series of decimal numbers, because the ID is of fixed length 5.
The first subproblem is to find the maximum ID, because it should be assumed that F9998 < F9999 < AA000 < AA001. We can calculate H*10000 + D with H being the hexadecimal part and D the decimal part of the ID to get the right order.
SELECT id
FROM (
SELECT 'AB999' as id UNION
SELECT 'AA000' UNION
SELECT 'F9999' UNION
SELECT 'AAA00' UNION
SELECT 'FFFF9' UNION
SELECT 'FFFF8' UNION
SELECT 'FFFD3') user
ORDER BY conv(regexp_substr(id, '^[A-F]*'), 16, 10) * 10000 + CAST(substring(id, length(regexp_substr(id, '^[A-F]*')) + 1) AS unsigned) DESC
LIMIT 1;
The second subproblem is to find the successor of a given ID. We calculate the decimal number like above but use the correct factor (10^n with n being the length of the decimal part) this time, then we add one to this number and convert it back to the hex/dec representation. In the hexadecimal part there may be 0s and 1s which have to be replaced by 'A'. Whenever the hex part gets longer, the decimal part consists of 0s only. That is, we can just return a substring of the desired length and strip trailing 0es:
DELIMITER //
CREATE FUNCTION nextId(id VARCHAR(5)) RETURNS VARCHAR(5) NO SQL
BEGIN
set @hexStr := regexp_substr(id, '^[A-F]*');
set @digits := length(id) - length(@hexStr);
set @decimalPart := CAST(right(id, @digits) AS UNSIGNED);
set @factor := pow(10, @digits);
set @hexPart := conv(@hexStr, 16, 10);
set @n := @hexPart * @factor + @decimalPart + 1; -- ID increased by 1
set @decimalPart := mod(@n, @factor);
set @hexStr := regexp_replace(conv(floor(@n / @factor), 10, 16), '[01]', 'A');
return substring(concat(@hexStr, lpad(@decimalPart, @digits, '0')), 1, length(id));
END;
//
DELIMITER ;
Using this function
SELECT id, nextId(id) next_id
FROM (
SELECT 'F9998' as id UNION
SELECT 'F9999' UNION
SELECT 'AA999' as id UNION
SELECT 'AB000' UNION
SELECT 'AB999' UNION
SELECT 'AF999' UNION
SELECT 'FF999' UNION
SELECT 'AAA00') user;
results in
id |
next_id |
F9998 |
F9999 |
F9999 |
AA000 |
AA999 |
AB000 |
AB000 |
AB001 |
AB999 |
AC000 |
AF999 |
BA000 |
FF999 |
AAA00 |
AAA00 |
AAA01 |
Here's a fiddle