SQL中FOR JSON PATH返回JSON数组而非对象的问题及解决
你遇到的这个情况挺常见的——FOR JSON PATH默认会把查询返回的行集包装成JSON数组,哪怕结果只有一行数据,它也会自动加上[]括号,所以你看到的[{"Name":"Value"}]就是这个默认行为导致的。
至于你用JSON_VALUE提取$[0]返回NULL,是因为JSON_VALUE只能提取标量值(比如字符串、数字这类单一值),而$[0]对应的是一个完整的JSON对象,不是标量类型,所以它会返回NULL。要提取JSON对象或数组,得用JSON_QUERY才行。
这里给你三种靠谱的解决办法,你可以根据自己的实际场景选择:
方法1:用WITHOUT_ARRAY_WRAPPER直接生成单个对象
这是最直接的方式,给FOR JSON PATH加上WITHOUT_ARRAY_WRAPPER选项,就能去掉默认的数组包装,直接返回单个JSON对象:
SELECT [JSON] = ( SELECT [Name] FROM OPENJSON(MyJsonColumn) WITH ([Name] nvarchar(50) '$.Name') FOR JSON PATH, WITHOUT_ARRAY_WRAPPER ) FROM MyTable
⚠️ 注意:如果OPENJSON返回多行数据(比如你的MyJsonColumn里有多个符合$.Name的节点),用这个参数会报错,因为它只能处理单行结果。如果你的场景里每个MyJsonColumn确实只有一个Name字段,这个方法完美适用。
方法2:用JSON_QUERY提取数组中的第一个对象
如果你不想修改原有的FOR JSON PATH逻辑,或者需要兼容可能的多行情况,也可以用JSON_QUERY提取数组的第一个元素:
SELECT [JSON] = JSON_QUERY( (SELECT [Name] FROM OPENJSON(MyJsonColumn) WITH ([Name] nvarchar(50) '$.Name') FOR JSON PATH), '$[0]' ) FROM MyTable
JSON_QUERY专门用来提取JSON对象或数组,所以这里能正确拿到{"Name":"Value"}这个目标对象。
方法3:直接提取值构造JSON(简单场景最优)
如果你的需求只是把MyJsonColumn里的$.Name提取出来封装成单个JSON对象,其实可以不用OPENJSON,直接用JSON_VALUE提取值后构造标准JSON:
SELECT [JSON] = JSON_OBJECT('Name', JSON_VALUE(MyJsonColumn, '$.Name')) FROM MyTable
这个方法更高效,因为它不需要解析整个JSON行集,直接定位到$.Name取值,而且JSON_OBJECT会自动处理特殊字符转义,比手动拼接字符串靠谱得多。
内容的提问来源于stack exchange,提问作者nalka

