本文主要介绍,在sqlserver存储过程中,使用JSON字符串作为入参,并解析使用。
JSON 相关的方法:
- ISJSON: 作用:判断一段字符串是否是标准的 json
- FOR JSON PATH:作用:直接查询数据成 json 格式 ,类似于之前的查询一个 xml (FOR XML PATH)
- JSON_VALUE:作用:获取json中的节点值,获取json中的节点值,包含标量值、嵌套对象属性
- JSON_QUERY:作用:提取嵌套对象和嵌套数组
- JSON_MODIFY:作用:更新一段JSON的内容,修改 JSON 对象里的属性值,删除 JSON 对象里的某一个属性,增加属性
- OPENJSON:解析一段 json 内容
使用示例:
以下json字符串示例中,包含嵌套对象、数组,后面以此json为示例演示。
sql
DECLARE @json NVARCHAR(MAX) = N'{
"student_id": 10,
"student_name": "张三",
"student_age": 18,
"student_class": {
"class_id": 2,
"class_code": "snj2",
"class_name": "三年级2班"
},
"student_subjects": [
{
"subject_id": 1,
"subject_name": "语文"
},
{
"subject_id": 2,
"subject_name": "数学"
}
]
}';
在JSON中,分为标量值可非标量值:
- 标量值:
- 定义:单一的、不可再分解的基础数据类型
- 例如:上面JSON串,顶层字段student_id、student_name、student_age
- 非标量值:
- 定义:可包含多个元素或键值对的复合数据结构
- 例如:上面JSON串,student_class节点(嵌套对象),student_subjects(嵌套数组)
结构类型 | 路径表达式 | 数据类型 |
---|---|---|
标量值 | $.student_id | 数值 |
标量值 | $.student_name | 字符串 |
标量值 | $.student_age | 数值 |
嵌套对象 | $.student_class | JSON 对象 |
嵌套数组 | $.student_subjects | JSON 数组 |
标量值
解析顶层字段标量值student_id、student_name、student_age
sql
--方法1,直接JSON_VALUE获取
--方法1,直接使用JSON_VALUE获取顶层标量字段
SELECT
JSON_VALUE(@json, '$.student_id') AS student_id,
JSON_VALUE(@json, '$.student_name') AS student_name,
JSON_VALUE(@json, '$.student_age') AS student_age
--方法2,使用OPENJSON解析
SELECT
id as student_id,
name as student_name,
age as student_age
FROM OPENJSON(@json) WITH (
id INT '$.student_id',
name NVARCHAR(50) '$.student_name',
age INT '$.student_age'
);

嵌套对象
获取非标量值嵌套对象student_class节点中的class_id、class_code、class_name
sql
--方法1,直接使用JSON_VALUE,通过$.student_class.xx获取
SELECT
JSON_VALUE(@json, '$.student_class.class_id') AS class_id,
JSON_VALUE(@json, '$.student_class.class_code') AS class_code,
JSON_VALUE(@json, '$.student_class.class_name') AS class_name
--方法2,使用OPENJSON解析,用$.student_class.xx获取
SELECT
class_id,
class_code,
class_name
FROM OPENJSON(@json) WITH (
class_id NVARCHAR(50) '$.student_class.class_id',
class_code NVARCHAR(50) '$.student_class.class_code',
class_name NVARCHAR(50) '$.student_class.class_name'
) AS class
--方法3,先JSON_QUERY获取student_class节点,然后OPENJSON解析
SELECT
class_id,
class_code,
class_name
FROM OPENJSON(JSON_QUERY(@json, '$.student_class'))
WITH (
class_id NVARCHAR(50) '$.class_id',
class_code NVARCHAR(50) '$.class_code',
class_name NVARCHAR(50) '$.class_name'
) AS class

嵌套数组
获取非标量嵌套数组student_subjects中的属性值
sql
--直接使用JSON_VALUE? 不可以,获取不到
SELECT
JSON_VALUE(@json, '$.student_subjects.subject_id') AS class_id,
JSON_VALUE(@json, '$.student_subjects.subject_name') AS class_code
--使用OPENJSON解析+$.student_subjects.xx读取? 不可以,获取不到
SELECT
subject_id,
subject_name
FROM OPENJSON(@json) WITH (
subject_id NVARCHAR(50) '$.student_subjects.subject_id',
subject_name NVARCHAR(50) '$.student_subjects.subject_name'
) AS subject
--正确方法:先使用JSON_QUERY获取$.student_subjects节点,再OPENJSON解析
SELECT
subject_id,
subject_name
FROM OPENJSON(JSON_QUERY(@json, '$.student_subjects'))
WITH (
subject_id INT '$.subject_id',
subject_name NVARCHAR(50) '$.subject_name'
) AS subject;

普通数组
sql
--基本类型数组
DECLARE @json NVARCHAR(MAX) = N'[
10,
20,
30
]';
SELECT value AS Number
FROM OPENJSON(@json);
--引用类型数组
DECLARE @json2 NVARCHAR(MAX) = N'[
{"id":1,"name":"张三"},
{"id":2,"name":"李四"}
]';
SELECT
id,
name
FROM OPENJSON(@json2)
WITH ( --虚拟表映射
id INT '$.id', -- 提取每个对象的id字段
name NVARCHAR(50) '$.name' -- 提取每个对象的name字段
);

简单存储过程使用示例:
下面还是通过上面的JSON字符串示例,演示一下如何存储过程使用JSON字符串接收,并在其中解析使用等。
sql
ALTER PROCEDURE ParseStudentJson
@json NVARCHAR(MAX)
AS
BEGIN
--json示例
--DECLARE @json NVARCHAR(MAX) = N'{
-- "student_id": 10,
-- "student_name": "张三",
-- "student_age": 18,
-- "student_class": {
-- "class_id": 2,
-- "class_code": "snj2",
-- "class_name": "三年级2班"
-- },
-- "student_subjects": [
-- {
-- "subject_id": 1,
-- "subject_name": "语文"
-- },
-- {
-- "subject_id": 2,
-- "subject_name": "数学"
-- }
-- ]
--}';
-- 验证 JSON 格式
IF ISJSON(@json) = 0
BEGIN
RAISERROR('输入参数不是有效的 JSON 格式', 16, 1);
RETURN;
END
create table #student(
student_id int,
student_name varchar(50),
student_age int
)
create table #student_class(
class_id int,
class_code varchar(50),
class_name varchar(50),
student_id int
)
create table #student_subject(
subject_id int,
subject_name varchar(50),
student_id int
)
-- 解析学生信息 方法1
INSERT INTO #student (student_id, student_name, student_age)
SELECT
JSON_VALUE(@json, '$.student_id') AS student_id,
JSON_VALUE(@json, '$.student_name') AS student_name,
JSON_VALUE(@json, '$.student_age') AS student_age
/**
解析顶层字段 方法2
INSERT INTO #student (student_id, student_name, student_age)
SELECT
id as student_id,
name as student_name,
age as student_age
FROM OPENJSON(@json) WITH (
id INT '$.student_id',
name NVARCHAR(50) '$.student_name',
age INT '$.student_age'
);
**/
-- 解析班级信息 方法1
INSERT INTO #student_class (class_id, class_code, class_name, student_id)
SELECT
JSON_VALUE(@json, '$.student_class.class_id') AS class_id,
JSON_VALUE(@json, '$.student_class.class_code') AS class_code,
JSON_VALUE(@json, '$.student_class.class_name') AS class_name,
JSON_VALUE(@json, '$.student_id') AS student_id
/**
解析班级信息 方法2
INSERT INTO #student_class (class_id, class_code, class_name, student_id)
SELECT
class_id,
class_code,
class_name,
student_id
FROM OPENJSON(@json) WITH (
class_id NVARCHAR(50) '$.student_class.class_id',
class_code NVARCHAR(50) '$.student_class.class_code',
class_name NVARCHAR(50) '$.student_class.class_name'
) AS class
CROSS APPLY (SELECT student_id FROM #student) AS s; --CROSS APPLY:动态关联,右侧子查询可引用左侧表的列,类似逐行处理,有一点点类似join的感觉
**/
/**
解析班级信息 方法3
INSERT INTO #student_class (class_id, class_code, class_name, student_id)
SELECT
class_id,
class_code,
class_name,
student_id
FROM OPENJSON(JSON_QUERY(@json, '$.student_class'))
WITH (
class_id NVARCHAR(50) '$.class_id',
class_code NVARCHAR(50) '$.class_code',
class_name NVARCHAR(50) '$.class_name'
) AS class
CROSS APPLY (SELECT student_id FROM #student) AS s;
**/
-- 解析学科信息
INSERT INTO #student_subject (subject_id, subject_name, student_id)
SELECT
subject_id,
subject_name,
student_id
FROM OPENJSON(JSON_QUERY(@json, '$.student_subjects'))
WITH (
subject_id INT '$.subject_id',
subject_name NVARCHAR(50) '$.subject_name'
) AS subject
CROSS APPLY (SELECT student_id FROM #student) AS s;
--这里为了方便,只是往临时表写了数据并查出来,实际业务可以是根据入参,去更新、删除业务表数据
select * from #student;
select * from #student_class;
select * from #student_subject;
drop table #student;
drop table #student_class;
drop table #student_subject;
END
总结:
- JSON_VALUE:
- 提取标量值,如上 JSON_VALUE(@json, '$.student_id')
- 提取嵌套对象属性,如上 JSON_VALUE(@json, '$.student_class.class_id')
- JSON_QUERY:
- 提取嵌套对象
- 提取嵌套数组
- OPENJSON:
- 解析JSON都要用到