MySQL 存储过程如何拆分并筛选正整数?
数据阿明
结论
当前描述的代码有几处相互独立的问题,可能导致结果不符合预期:调用使用逗号分隔,过程却按分号计算和拆分;过程把参数 variants 当作会话变量 @variants 使用;初始化 JSON 数组的方式也与预期结构不符。代码中还有截断和占位符,因此无法还原或确认原过程的完整语法。
输入也与预期结果不一致。CALL new_procedure('2, b7, vb, 9'); 中大于 0 的数字只有 2 和 9,不会产生 3 和 1。如果预期结果是 3、1、2、9,需要提供包含这些数字的实际输入。
主要问题
- 分隔符不一致:过程用
';'计算片段数量,也用';'调用split_string,但示例字符串使用逗号分隔。应统一使用逗号,或将调用字符串改为分号分隔。 - 参数引用错误:过程参数名是
variants,代码却调用split_string(@variants, ...)。@variants是会话变量,不会自动取得过程参数的值。这里应传入variants。 - JSON 初值不是预期的数字数组:
JSON_ARRAY('[3, 1]')创建的是一个包含字符串"[3, 1]"的数组,而不是包含数字3和1的数组。因此,追加和JSON_TABLE处理的结构可能与预期不同。 - 输入片段数可能与结果数量混淆:
@params_number统计输入片段数,而结果只保留有效数字。用两者比较来判断结果是否有效,不能说明数组内容正确。如果初始数组还包含一个字符串,长度比较也会进一步偏离预期。 - 代码片段不完整:
JSON_TABLE的列定义、函数中的正则表达式和过程主体都被占位符或截断内容打断。需要完整 SQL 才能确认这些部分是否还有语法错误。
一种实现方式
如果使用 MySQL 8.0,可以在过程内用递归 CTE 拆分逗号分隔的字符串,再筛选由数字组成且大于 0 的片段:
DELIMITER //
CREATE PROCEDURE new_procedure(IN variants VARCHAR(250))
BEGIN
WITH RECURSIVE parts AS (
SELECT
SUBSTRING_INDEX(variants, ',', 1) AS part,
CASE
WHEN LOCATE(',', variants) > 0
THEN SUBSTRING(variants, LOCATE(',', variants) + 1)
ELSE ''
END AS rest
UNION ALL
SELECT
SUBSTRING_INDEX(rest, ',', 1) AS part,
CASE
WHEN LOCATE(',', rest) > 0
THEN SUBSTRING(rest, LOCATE(',', rest) + 1)
ELSE ''
END AS rest
FROM parts
WHERE rest <> ''
)
SELECT CAST(TRIM(part) AS UNSIGNED) AS variant_number
FROM parts
WHERE TRIM(part) REGEXP '^[0-9]+$'
AND CAST(TRIM(part) AS UNSIGNED) > 0;
END//
DELIMITER ;
调用:
CALL new_procedure('2, b7, vb, 9');
这个输入会返回一列 variant_number,值为 2 和 9。b7 和 vb 不符合纯数字格式,会被过滤。TRIM 会去掉片段两侧的空格。
注意事项
此示例按逗号拆分字符串,并依赖 MySQL 8.0 的递归 CTE 支持。如果实际需要使用分号,应将代码中的逗号分隔符改为分号。要核对原存储过程本身的具体错误,还需要提供未截断的过程和函数定义,以及能对应预期输出的输入值。
备注:内容仅供参考。
