sqlserver存储过程中入参使用JSON

本文主要介绍,在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都要用到
相关推荐
一 乐5 小时前
民宿|基于java的民宿推荐系统(源码+数据库+文档)
java·前端·数据库·vue.js·论文·源码
美林数据Tempodata7 小时前
大模型驱动数据分析革新:美林数据智能问数解决方案破局传统 BI 痛点
数据库·人工智能·数据分析·大模型·智能问数
野槐7 小时前
node.js连接mysql写接口(一)
数据库·mysql
Zzzone6837 小时前
PostgreSQL日常维护
数据库·postgresql
chxii8 小时前
1.13使用 Node.js 操作 SQLite
数据库·sqlite·node.js
冰刀画的圈8 小时前
修改Oracle编码
数据库·oracle
这个胖子不太裤8 小时前
Django(自用)
数据库·django·sqlite
麻辣清汤8 小时前
MySQL 索引类型及其必要性与优点
数据库·mysql
2501_915374359 小时前
Neo4j 图数据库安装教程(2024最新版)—— Windows / Linux / macOS 全平台指南
数据库·windows·neo4j
it-搬运工9 小时前
3.图数据Neo4j - CQL的使用
数据库·neo4j