SQL Server 2022 新特性:JSON_OBJECT、JSON_ARRAY、JSON_PATH_EXISTS 详解

前言

JSON 已经成为现代应用数据交换的主流格式。SQL Server 2016 起就支持了 FOR JSONOPENJSONJSON_VALUE 等基础 JSON 功能,但构建 JSON 对象和数组 一直要依赖 FOR JSON PATH 这类写法,比较繁琐。

SQL Server 2022 新增了三个 JSON 函数,直击痛点:

函数 作用
JSON_OBJECT() 直接用键值对构建 JSON 对象
JSON_ARRAY() 直接用值列表构建 JSON 数组
JSON_PATH_EXISTS() 检测 JSON 字符串中是否存在指定路径

本文通过完整可运行的示例,带你掌握这三个函数的用法。


准备测试数据

复制代码
-- 创建员工信息表
CREATE TABLE Employees (
    EmpID       INT           PRIMARY KEY,
    Name        NVARCHAR(50),
    Department  NVARCHAR(50),
    Salary      DECIMAL(10,2),
    Skills      NVARCHAR(200),   -- 逗号分隔的技能列表
    Profile     NVARCHAR(MAX)    -- 存储 JSON 格式的扩展信息
);

INSERT INTO Employees VALUES
(1, N'张伟',   N'研发部', 18000.00, N'C#,SQL,Azure',
 N'{"age":30,"city":"北京","certified":true}'),
(2, N'李娜',   N'数据部', 16000.00, N'Python,SQL,Power BI',
 N'{"age":28,"city":"上海","certified":false}'),
(3, N'王磊',   N'研发部', 20000.00, N'Java,SQL,Docker',
 N'{"age":35,"city":"深圳","certified":true}'),
(4, N'赵敏',   N'运营部', 12000.00, N'Excel,SQL',
 N'{"age":26,"city":"成都"}'),           -- 注意:没有 certified 字段
(5, N'陈静',   N'数据部', 17500.00, N'R,Python,Tableau',
 N'{"age":31,"city":"杭州","certified":true}');

示例一:JSON_OBJECT() --- 构建 JSON 对象

语法:

复制代码
JSON_OBJECT ( key_value_pair [, ...] [ NULL ON NULL | ABSENT ON NULL ] )
  • key : value 用冒号分隔
  • NULL ON NULL(默认):值为 NULL 时,输出 "key": null
  • ABSENT ON NULL:值为 NULL 时,整个键值对不出现在结果中

示例:为每位员工生成简单 JSON 名片

复制代码
SELECT
    EmpID,
    JSON_OBJECT(
        'name'      : Name,
        'dept'      : Department,
        'salary'    : Salary
    ) AS JsonCard
FROM Employees;

结果:

EmpID JsonCard
1 {"name":"张伟","dept":"研发部","salary":18000.00}
2 {"name":"李娜","dept":"数据部","salary":16000.00}
3 {"name":"王磊","dept":"研发部","salary":20000.00}
4 {"name":"赵敏","dept":"运营部","salary":12000.00}
5 {"name":"陈静","dept":"数据部","salary":17500.00}

示例:演示 NULL ON NULL vs ABSENT ON NULL

复制代码
-- 构造一行含 NULL 值的测试数据
DECLARE @Name  NVARCHAR(50) = N'测试员工';
DECLARE @Phone NVARCHAR(20) = NULL;   -- 手机号未填

-- 默认 NULL ON NULL:NULL 值以 null 出现在 JSON 中
SELECT JSON_OBJECT(
    'name'  : @Name,
    'phone' : @Phone
) AS WithNull;

-- ABSENT ON NULL:NULL 值对应的键直接省略
SELECT JSON_OBJECT(
    'name'  : @Name,
    'phone' : @Phone
    ABSENT ON NULL
) AS WithoutNull;

结果:

模式 输出
NULL ON NULL(默认) {"name":"测试员工","phone":null}
ABSENT ON NULL {"name":"测试员工"}

使用场景 :向前端返回数据时,通常推荐 ABSENT ON NULL,可以减少不必要的空字段,降低传输体积。


示例二:JSON_ARRAY() --- 构建 JSON 数组

语法:

复制代码
JSON_ARRAY ( value [, ...] [ NULL ON NULL | ABSENT ON NULL ] )

示例:将技能字段拆分后重新组装为 JSON 数组

复制代码
-- 先用已有的字符串拼接演示基本用法
SELECT
    EmpID,
    Name,
    JSON_ARRAY(
        TRIM(value)     -- STRING_SPLIT 拆分出来的每项技能
    ) AS SkillItem
FROM Employees
CROSS APPLY STRING_SPLIT(Skills, ',');

注意:上面示例每行只输出单个技能元素(便于理解 JSON_ARRAY 用法),实际业务中通常配合子查询聚合。

示例:直接构建静态多值数组

复制代码
SELECT
    EmpID,
    Name,
    JSON_ARRAY(EmpID, Name, Department, Salary) AS InfoArray
FROM Employees;

结果:

EmpID Name InfoArray
1 张伟 [1,"张伟","研发部",18000.00]
2 李娜 [2,"李娜","数据部",16000.00]
3 王磊 [3,"王磊","研发部",20000.00]
4 赵敏 [4,"赵敏","运营部",12000.00]
5 陈静 [5,"陈静","数据部",17500.00]

示例:JSON_OBJECT 嵌套 JSON_ARRAY

复制代码
SELECT
    EmpID,
    JSON_OBJECT(
        'name'   : Name,
        'dept'   : Department,
        'skills' : JSON_ARRAY(
                       TRIM(s1.value),
                       TRIM(s2.value),
                       TRIM(s3.value)
                   ABSENT ON NULL
                   )
    ) AS RichCard
FROM Employees
OUTER APPLY (
    SELECT value FROM STRING_SPLIT(Skills, ',') ORDER BY (SELECT NULL) OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
) s1(value)
OUTER APPLY (
    SELECT value FROM STRING_SPLIT(Skills, ',') ORDER BY (SELECT NULL) OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
) s2(value)
OUTER APPLY (
    SELECT value FROM STRING_SPLIT(Skills, ',') ORDER BY (SELECT NULL) OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY
) s3(value);

两个函数可以自由嵌套,轻松构造复杂 JSON 结构:

结果示例:


示例三:JSON_PATH_EXISTS() --- 检测 JSON 路径是否存在

语法:

复制代码
JSON_PATH_EXISTS ( json_expression , sql_json_path )

返回 1(路径存在)或 0(路径不存在),若输入 JSON 无效或为 NULL 则返回 NULL。

示例:找出 Profile 中含有 "certified" 字段的员工

复制代码
SELECT
    EmpID,
    Name,
    Profile,
    JSON_PATH_EXISTS(Profile, '$.certified') AS HasCertified
FROM Employees;

结果:

EmpID Name Profile HasCertified
1 张伟 {"age":30,"city":"北京","certified":true} 1
2 李娜 {"age":28,"city":"上海","certified":false} 1
3 王磊 {"age":35,"city":"深圳","certified":true} 1
4 赵敏 {"age":26,"city":"成都"} 0
5 陈静 {"age":31,"city":"杭州","certified":true} 1

赵敏的 Profile 里没有 certified 字段,返回 0;其余都有,返回 1


示例:过滤 + 结合 WHERE 子句

复制代码
-- 只查有认证信息 且 已认证的员工
SELECT
    EmpID,
    Name,
    JSON_VALUE(Profile, '$.certified') AS IsCertified
FROM Employees
WHERE JSON_PATH_EXISTS(Profile, '$.certified') = 1
  AND JSON_VALUE(Profile, '$.certified') = 'true';

结果:

EmpID Name IsCertified
1 张伟 true
3 王磊 true
5 陈静 true

示例:嵌套路径检测

复制代码
-- 假设部分员工 Profile 有嵌套结构
UPDATE Employees
SET Profile = N'{"age":30,"city":"北京","certified":true,"contact":{"email":"zhangwei@example.com"}}'
WHERE EmpID = 1;

-- 检测嵌套路径是否存在
SELECT
    EmpID,
    Name,
    JSON_PATH_EXISTS(Profile, '$.contact.email') AS HasEmail,
    JSON_PATH_EXISTS(Profile, '$.contact.phone') AS HasPhone
FROM Employees
WHERE EmpID = 1;

结果:

EmpID Name HasEmail HasPhone
1 张伟 1 0

与旧版写法对比

构建 JSON 对象

旧写法(SQL Server 2016~2019):

复制代码
-- 方法一:FOR JSON PATH(需要 SELECT 子查询)
SELECT (
    SELECT Name AS name, Department AS dept, Salary AS salary
    FROM Employees
    WHERE EmpID = 1
    FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) AS JsonCard;

-- 方法二:字符串拼接(最原始,容易出错)
SELECT
    '{"name":"' + Name + '","dept":"' + Department + '"}'
FROM Employees;

新写法(SQL Server 2022):

复制代码
SELECT
    JSON_OBJECT('name': Name, 'dept': Department, 'salary': Salary)
FROM Employees;

对比总结:

维度 旧写法(FOR JSON PATH) 新写法(JSON_OBJECT)
代码量 多,需要子查询 少,内联即可
可读性 较低 直观清晰
嵌套支持 麻烦 直接嵌套调用
NULL 处理 不灵活 支持 ABSENT ON NULL

检测 JSON 路径

旧写法:

复制代码
-- 用 JSON_VALUE 返回 NULL 来"间接"判断路径是否存在,有歧义
-- (NULL 可能是路径不存在,也可能是路径存在但值本身是 null)
SELECT *
FROM Employees
WHERE JSON_VALUE(Profile, '$.certified') IS NOT NULL;

新写法:

复制代码
-- JSON_PATH_EXISTS 语义明确,无歧义
SELECT *
FROM Employees
WHERE JSON_PATH_EXISTS(Profile, '$.certified') = 1;

旧写法的致命缺陷:如果 JSON 中 "certified": nullJSON_VALUE 返回 NULL,会被误判为路径不存在。JSON_PATH_EXISTS 彻底解决了这个问题。


兼容性说明

功能 最低版本
JSON_OBJECT() SQL Server 2022(16.x)
JSON_ARRAY() SQL Server 2022(16.x)
JSON_PATH_EXISTS() SQL Server 2022(16.x)
Azure SQL Database 已支持(同步更新)
Azure SQL Managed Instance 已支持
SQL Server 2019 及更早 不支持,需用 FOR JSON / 字符串拼接替代

如果生产环境还在使用 SQL Server 2019,可用 FOR JSON PATH + 子查询实现相近效果,但语法相对繁琐。


总结

SQL Server 2022 的三个新 JSON 函数让 JSON 构建和查询更加简洁直观:

  1. JSON_OBJECT() :用键值对语法直接构造 JSON 对象,支持 ABSENT ON NULL 控制空值输出,可自由嵌套。

  2. JSON_ARRAY() :用值列表直接构造 JSON 数组,同样支持 ABSENT ON NULL,与 JSON_OBJECT() 嵌套使用可构建任意复杂的 JSON 结构。

  3. JSON_PATH_EXISTS() :精准判断 JSON 路径是否存在,返回 0/1,语义清晰,彻底解决了旧版用 JSON_VALUE IS NOT NULL 判断带来的歧义问题。

这三个函数在实际项目中的典型使用场景:

  • API 数据封装:直接在 SQL 层组装 JSON 返回给接口,减少应用层代码
  • 动态配置查询 :用 JSON_PATH_EXISTS 先检测字段再读取,避免报错
  • 数据迁移转换:将关系型数据直接转为 JSON 格式写入文档型存储

升级到 SQL Server 2022 后,建议优先用这三个函数替换项目中的 FOR JSON PATH 拼接写法,代码会更简洁、可维护性更强。

相关推荐
HIT_Weston2 小时前
47、【Agent】【OpenCode】本地代理增强版分析(JSON解析)
人工智能·json·agent·opencode
SuperEugene1 天前
Vue3 配置驱动弹窗:JSON配置弹窗内容/按钮,避免重复开发弹窗|配置驱动开发实战篇
前端·javascript·vue.js·前端框架·json
五仁火烧1 天前
前端最常用的两种请求数据格式application/json 和 multipart/form-data 完全解析
前端·javascript·vue.js·json
吹个口哨写代码1 天前
h5/小程序直接读本地/在线的json文件数据
前端·小程序·json
DevOpenClub2 天前
文章抽取信息化 JSON API 接口
json
电商API&Tina2 天前
1688 拍立淘接口(item_search_img)测试与接入实战心得
java·大数据·前端·物联网·oracle·json
ZC跨境爬虫2 天前
海南大学交友平台开发实战 day11(实现性别图标渲染与后端数据关联+Debug复盘)
前端·python·sqlite·html·json
被放养的研究生2 天前
vscode-settings.json
ide·vscode·json
SuperEugene2 天前
Vue3 配置驱动表单:JSON配置+渲染引擎,快速搭建复杂表单|配置驱动开发实战篇
驱动开发·json