MySQL存储过程不能用RETURN返回JSON,只能通过SELECT输出JSON字段;常用方式是JSON_ARRAYAGG+JSON_OBJECT构建数组或JSON_OBJECT直出单行,需注意空结果、NULL处理及JSON路径提取。

存储过程里不能用 RETURN 返回 JSON
MySQL 存储过程(CREATE PROCEDURE)没有 RETURN 语句,也不返回值;它只能通过 SELECT 向客户端“发送结果集”。所以所谓“返回 JSON”,本质是执行一条 SELECT 输出一个 JSON 类型字段。如果写成 RETURN @json 或类似函数写法,会直接报错 ERROR 1327 (42000): Undeclared variable 或语法错误。
常见误操作:
- 把函数写法套到存储过程里,比如加
RETURNS JSON—— 这在CREATE PROCEDURE中非法,MySQL 会拒绝解析 - 声明
DECLARE result JSON后只赋值不SELECT—— 客户端收不到任何数据,看似“没返回” - 用
SELECT JSON_OBJECT(...)但没加别名,导致字段名是JSON_OBJECT(...)这种表达式,调用方难引用
用 JSON_ARRAYAGG + JSON_OBJECT 构建多行 JSON 数组
这是最常用、最稳妥的方式:把查询结果的每一行转成 JSON 对象,再聚合成一个 JSON 数组。适用于返回列表类数据(如用户列表、订单列表)。
示例(MySQL 5.7+):
DELIMITER $$
CREATE PROCEDURE get_users_json()
BEGIN
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'id', u.id,
'name', u.name,
'email', u.email
)
) AS result
FROM users u
WHERE u.status = 'active';
END$$
DELIMITER ;注意点:
-
JSON_ARRAYAGG对空结果集返回NULL,不是[];如需空数组,可包装:COALESCE(JSON_ARRAYAGG(...), JSON_ARRAY()) - 字段名必须明确写出,不能用
*;否则JSON_OBJECT(*)不合法 - 若某列含
NULL,对应 JSON 字段仍存在,值为null(符合 JSON 标准)
单行数据优先用 JSON_OBJECT 直出
查一条记录时,没必要套一层数组。直接 SELECT JSON_OBJECT(...) 更轻量、结构更清晰。
示例:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
DELIMITER $$
CREATE PROCEDURE get_user_by_id(IN uid INT)
BEGIN
SELECT JSON_OBJECT(
'id', u.id,
'name', u.name,
'created_at', u.created_at,
'tags', u.tags -- 假设 tags 是 JSON 类型字段,原样透出
) AS result
FROM users u
WHERE u.id = uid;
END$$
DELIMITER ;关键细节:
- 如果被查记录不存在,整个
SELECT无结果行 → 客户端收到空结果集(0 行),不是NULL或{} - 若需保证总有返回(哪怕空对象),得加
LEFT JOIN或用IFNULL(..., JSON_OBJECT())包裹,但逻辑变重,慎用 - 避免在
JSON_OBJECT里嵌套子查询——MySQL 不允许,会报ERROR 1356 (HY000)
JSON 字段内容要原样透出?别直接拼,用 ->> 提取
表里已有 JSON 字段(如 ext_info),想把它某个子字段“扁平化”放进新 JSON,不能直接写 'extra', u.ext_info(会变成字符串转义),而要用 ->> 提取裸值。
错误写法:
JSON_OBJECT('extra', u.ext_info) -- 结果里 extra 是 ""{\"age\":25}"" 这种双重转义字符串正确写法:
JSON_OBJECT( 'age', u.ext_info->>'$.age', 'city', u.ext_info->>'$.address.city', 'hobbies', u.ext_info->>'$.hobbies' -- 注意:hobbies 是数组,->> 返回字符串 "["篮球","编程"]" )
补充说明:
-
->>等价于JSON_UNQUOTE(JSON_EXTRACT(...)),必须用它才能得到可参与比较或展示的裸值 - 对 JSON 数组字段,
->>返回的是 JSON 字符串(带引号和方括号),不是 PHP/Python 里的 list;前端需自行JSON.parse() - 路径错误或字段缺失时,
->>静默返回NULL,不会中断执行——这点容易被忽略,建议配合JSON_CONTAINS_PATH()做存在性校验
实际调用时,客户端收到的就是一行一列、类型为 JSON 的结果,字段名由 AS result 决定。真正麻烦的从来不是“怎么拼 JSON”,而是路径写错、NULL 处理遗漏、空结果集预期不符——这些地方一漏,前端就收不到数据,还查不出错在哪。

















