在 MySQL 中实现真正的字母数字排序(自然排序)确实是一个常见挑战,而且解决方案通常涉及递归或类似递归的技术。让我解释为什么会出现这种情况以及如何解决。
字母数字排序(如 "item1", "item2", "item10" 按数字顺序排列)在 MySQL 中不是默认行为的原因:
SELECT column_name
FROM table_name
ORDER BY
CAST(REGEXP_SUBSTR(column_name, '[0-9]+') AS UNSIGNED),
column_name;
WITH RECURSIVE split_string AS (
SELECT
column_name,
REGEXP_REPLACE(column_name, '[0-9]+', '') AS text_part,
REGEXP_REPLACE(column_name, '[^0-9]+', '') AS num_part
FROM table_name
)
SELECT column_name
FROM split_string
ORDER BY text_part, CAST(num_part AS UNSIGNED);
对于更复杂的情况,可以创建存储函数:
DELIMITER //
CREATE FUNCTION natural_sort_key(s VARCHAR(255)) RETURNS VARCHAR(255) DETERMINISTIC
BEGIN
DECLARE result VARCHAR(255) DEFAULT '';
DECLARE i INT DEFAULT 1;
DECLARE len INT;
DECLARE c CHAR(1);
DECLARE is_num BOOLEAN DEFAULT FALSE;
SET len = CHAR_LENGTH(s);
WHILE i <= len DO
SET c = SUBSTRING(s, i, 1);
IF c BETWEEN '0' AND '9' THEN
IF NOT is_num THEN
SET result = CONCAT(result, ' ');
SET is_num = TRUE;
END IF;
ELSE
SET is_num = FALSE;
END IF;
SET result = CONCAT(result, c);
SET i = i + 1;
END WHILE;
RETURN result;
END //
DELIMITER ;
-- 使用
SELECT column_name FROM table_name ORDER BY natural_sort_key(column_name);
在 MySQL 8.0 之前,没有内置函数可以直接实现这种排序,因此开发者需要创造性地使用字符串函数组合或存储过程来模拟递归处理。
MySQL 8.0+ 的 CTE 功能使得这种递归处理更加直观和高效。