登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

MySQL JSON_EXTRACT 返回带引号怎样处理

来源:17golang原创

时间:2026-10-23 03:52:56 440浏览 收藏

MySQL 的 JSON_EXTRACT 返回字符串时带双引号,是因为它返回 JSON 值,而 JSON 字符串的表示本来就包含引号。需要普通文本时,使用 JSON_UNQUOTE(JSON_EXTRACT(doc, '$.name'));若 doc 是 JSON 列,也可写成 doc->>'$.name'。不要用 REPLACE 删除所有双引号,那会把内容里的合法字符也删掉。

官方地址:https://dev.mysql.com/doc/refman/8.4/en/json-search-functions.html

先决定返回的是 JSON 还是业务文本,再选择提取表达式。去引号只解决字符串表示,不能替你决定缺失字段、JSON null、数字和数组应该如何映射。

如果是我接手这个字段,会先问调用方要什么

设想一个商品目录查询,JSON 文档中存着商品名称,页面只想展示名称,却拿到了带引号的结果。这里是教学场景,不是本人线上事故或实测记录。我的取舍会先从接口契约开始:如果调用方还要继续做 JSON 运算,我会保留 JSON 值;如果它只需要展示文本,我会在查询边界明确转换。

我不倾向于在每个页面再写一次“删引号”的补丁。这样看起来改动小,但接口、报表和导出容易得到不同结果。对我来说,明确一个字段的返回类型比让某个客户端表格暂时好看更重要;不过,通用 JSON 浏览器需要保留类型信息,就不适合把所有值都一律转成字符串。

两种表达式看起来相近,职责并不相同

以下查询只用表达式构造文档,不建表、不修改业务数据。示例按 MySQL 8.4 文档语义说明,没有在本机执行,结果描述是供读者运行时对照的预期。

-- JSON_OBJECT 构造本次原创样例,分别观察 JSON 值、文本和类型
SELECT
    JSON_EXTRACT(doc, '$.name') AS name_json,
    JSON_UNQUOTE(JSON_EXTRACT(doc, '$.name')) AS name_text,
    JSON_TYPE(JSON_EXTRACT(doc, '$.name')) AS name_kind
FROM (
    SELECT JSON_OBJECT('name', '轻量收纳盒', 'stock', 24) AS doc
) AS sample;

预期 name_json 表示 JSON 字符串,name_text 是普通名称文本,name_kind 为 STRING。客户端可能对字符串再加显示装饰,因此不要只靠界面里的引号判断 SQL 返回类型。先看表达式,再看类型和应用读取方式。

业务要求表达式选择需要接受的边界
保留 JSON 类型做后续运算JSON_EXTRACT字符串保持 JSON 表示
提取名称等文本JSON_UNQUOTE(JSON_EXTRACT(...))返回文本,仍需制定缺失策略
固定 JSON 列与固定路径的简洁写法列 ->> 路径是解引号提取,不代表数值类型转换
JSON 文档、提取表达式与文本返回契约的静态关系
图1:返回契约结构图。保留 JSON 与提取文本是两种用途,不是截图或实测结果。

我不会用字符串替换去修 JSON 转义

最容易被忽略的是名称本身就可能有双引号。比如品名里包含 12" 收纳盒,JSON 表示会对其中的引号做转义;它不是多余字符。删掉所有双引号,或者机械截掉首尾字符,都没有真正执行 JSON 字符串解码。

-- 用 CHAR(34) 构造合法双引号,避免手写多层反斜杠
SELECT
    JSON_EXTRACT(doc, '$.name') AS encoded_value,
    JSON_UNQUOTE(JSON_EXTRACT(doc, '$.name')) AS decoded_text
FROM (
    SELECT JSON_OBJECT('name', CONCAT('12', CHAR(34), ' 收纳盒')) AS doc
) AS sample;

decoded_text 预期保留名称中真正的双引号,而不是把它删除。需要特别注意 SQL 字符串字面量与 JSON 转义是两层规则;手写反斜杠的示例还可能受 SQL mode 影响。这里用 JSON_OBJECT 和 CHAR 构造输入,重点放在返回类型,不让转义层数盖过问题本身。

缺失、JSON null 和字符串 null 不能混成一种值

只看解引号后的文字,有时无法区分原始类型。例如 JSON null 与字符串 "null" 在转换成文本后容易被调用方混淆。路径根本不存在又是另一种情况。我的建议是:名称字段先限制为 JSON STRING,其他情况按业务映射为 SQL NULL,必要时另外输出状态字段。

-- 五组输入分别保留原始 JSON 类型,只把真正的字符串作为名称
WITH samples AS (
    SELECT 1 AS id, JSON_OBJECT('name', '轻量收纳盒') AS doc
    UNION ALL SELECT 2, JSON_OBJECT('name', NULL)
    UNION ALL SELECT 3, JSON_OBJECT('name', 'null')
    UNION ALL SELECT 4, JSON_OBJECT()
    UNION ALL SELECT 5, JSON_OBJECT('name', 24)
),
extracted AS (
    SELECT id, JSON_EXTRACT(doc, '$.name') AS value_json
    FROM samples
)
SELECT
    id,
    JSON_TYPE(value_json) AS value_kind,
    value_json IS NULL AS is_sql_null,
    CASE
        -- 只接受字符串;JSON null、路径缺失和错误业务类型均不冒充名称
        WHEN JSON_TYPE(value_json) = 'STRING'
        THEN JSON_UNQUOTE(value_json)
        ELSE NULL
    END AS name_text
FROM extracted
ORDER BY id;

按这份名称契约,第 1、3 行返回文本,其中第 3 行的 null 是四个字母,不是空值。第 2 行原始类型为 JSON 的 NULL,第 4 行路径缺失得到 SQL NULL,第 5 行原始类型是整数;这三行的 name_text 都映射为 SQL NULL。这里主动合并了非字符串情况,若业务需要分别报“未填写”与“类型错误”,就保留 value_kind 或另加状态列,不要丢掉判断依据。

路径缺失、JSON null、字符串及类型约束的静态关系
图2:类型策略结构图。业务文本与原始 JSON 类型分开表达,不把 null 文字误作空值。

查询已经转换,接口为什么仍显示反斜杠?

SQL 结果、数据库驱动读取值和最终 HTTP JSON 响应,是不同边界。即使 SQL 已经返回普通文本,把它放进 JSON 响应时,序列化器仍然需要给字符串加引号,并转义字符串内部的引号;这是合法的响应编码,不一定是重复编码。

真正的问题是把已经序列化成 JSON 字符串的片段当成普通文本,再序列化一次。排查时我会看调用方实际解析后的字段,而不只看原始响应字节里有没有反斜杠。对查询层的取舍也保持克制:只是为了展示名称,就取文本;需要数字参与排序或计算,就定义数值类型转换和非法值规则,不能因为 ->> 去掉了引号就认定得到了数值。

如果该路径频繁用于筛选,去引号并不自动解决索引与执行计划问题。生成列或表达式索引需要另外按目标版本、类型、长度和比较规则设计;本文没有执行计划或性能测量,不声称替换一个函数就会更快。大小写、排序规则和字符长度也应与接口契约一起明确。

数组或对象调用 JSON_UNQUOTE 会展开成多行吗?

不会。它不是数组展开工具。若读取到容器,应保留 JSON、另选具体元素路径,或为展开任务使用相应方案,不要期待它自动变成业务名称。

SQL NULL 能用等号判断吗?

应使用 IS NULL 判断 SQL 空值;它不等于字符串 'null',也不能直接代替 JSON 类型判断。

什么情况下我会保留带引号的结果?

当后续仍按 JSON 值处理,或者调用方需要区分字符串、数字和容器时,我会保留 JSON_EXTRACT 的类型语义。展示字段的简洁不应以丢失数据含义为代价。

参考:JSON 提取与解引号操作符;JSON_UNQUOTE;JSON_TYPE。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>