SQL for JSON

news2024/11/29 2:43:24

SQL for JSON

MySQL 提供了强大的 JSON 支持,使开发者能够高效地存储和查询结构化数据。下面,我们通过实例来介绍 MySQL 的 JSON 基本用法,包括如何存储、查询、更新和操作 JSON 数据。


1. 创建一个带有 JSON 列的表

我们可以将 JSON 数据类型用于表中的字段,例如:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    profile JSON
);

解释

  • profile 列的类型为 JSON,专门用于存储 JSON 数据。
  • name 列用于存储用户的名称。

2. 插入 JSON 数据

可以直接插入符合 JSON 格式的数据:

INSERT INTO users (name, profile) 
VALUES 
('Alice', '{"age": 25, "city": "New York", "skills": ["MySQL", "Python"]}'),
('Bob', '{"age": 30, "city": "San Francisco", "skills": ["Java", "C++"]}');

注意:插入的数据必须是有效的 JSON 格式,否则 MySQL 会报错。


3. 查询 JSON 数据

MySQL 提供了很多内置函数来操作 JSON 数据。

(1) 提取 JSON 数据 (->->>)

  • -> 用于获取 JSON 对象中的子对象。
  • ->> 用于获取 JSON 数据的字符串值。
-- 获取 Alice 的城市
SELECT name, profile->>'$.city' AS city 
FROM users 
WHERE name = 'Alice';

结果

+-------+-----------+
| name  | city      |
+-------+-----------+
| Alice | New York  |
+-------+-----------+

(2) 查询嵌套属性

JSON 路径支持深层嵌套查询:

-- 查询技能中的第一个值
SELECT name, profile->'$.skills[0]' AS first_skill 
FROM users;

结果

+-------+-------------+
| name  | first_skill |
+-------+-------------+
| Alice | "MySQL"     |
| Bob   | "Java"      |
+-------+-------------+

也可以使用JSON_EXTRACT获取指定的数据

1:mysql> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]');
结果: 202:mysql> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]', '$[0]'); 
结果: [20, 10] --多个值拼接为数组3:mysql> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[2][*]'); 
结果: [30, 40]

JSON不同于字符串,如果直接和整个JSON字段比较,不会查询到结果

SELECT * FROM muscleape WHERE category = '{"id": 1,"name": "muscleape"}';----结果查询不到数据。

这时候需要利用CAST把字符串转化成为JSON

SELECT * FROM muscleape WHERE category = CAST('{"id": 1,"name": "muscleape"}' AS JSON);
这样就可以正常找到结果了

还可以利用JSON_CONTAINS查找内部值

SELECT * FROM muscleape 
WHERE JSON_CONTAINS(category,  '1',  '$.id');-- 可以查询到数据
注意第二个参数只能是字符串

4. 更新 JSON 数据

可以使用 JSON_SETJSON_REMOVE 等函数更新 JSON 数据。

(1) 更新 JSON 中的值

-- 将 Alice 的城市改为 "Los Angeles"
UPDATE users 
SET profile = JSON_SET(profile, '$.city', 'Los Angeles') 
WHERE name = 'Alice';

JSON_SET( )函数——插入新值,并覆盖已存在的值
UPDATE muscleape SET category = JSON_SET(category,
'$.host’,  'localhost’,   '$.url',  'www.muscleape.com') 
WHERE id = 1;

JSON_REPLACE( )函数——只替换已存在的值
UPDATE muscleape SET category = JSON_REPLACE(category,
'$.host',  '127.0.0.1',   '$.address',  'shandong') 
WHERE id = 1;

(2) 删除 JSON 中的属性

-- 删除 Bob 的技能信息
UPDATE users 
SET profile = JSON_REMOVE(profile, '$.skills') 
WHERE name = 'Bob';

(3) 插入值

UPDATE muscleape SET category = JSON_INSERT(category,
    '$.name', 'muscleape_new',  '$.url', 'muscleape.com')  WHERE id = 1;
-----当JSON数据中已经存在name属性而没有url属性时,name值不会被修改,而url的值被添加进去。


5. 查询包含特定 JSON 数据的行

使用 JSON_CONTAINS 函数检查 JSON 中是否包含特定值。

-- 查询拥有 "Python" 技能的用户
SELECT name 
FROM users 
WHERE JSON_CONTAINS(profile->'$.skills', '"Python"');

结果

+-------+
| name  |
+-------+
| Alice |
+-------+

7. 聚合和复杂查询

MySQL 的 JSON 函数可以与其他 SQL 语法结合,进行复杂的数据分析。

-- 统计用户的年龄总和
SELECT SUM(profile->>'$.age') AS total_age 
FROM users;

在 MySQL 中,JSON_ARRAYAGGJSON_OBJECTAGG 是两个用于聚合数据的函数,它们的输出形式分别为 JSON 数组和 JSON 对象。这两个函数常用于将关系型数据转化为 JSON 格式,便于前端处理或其他用途。


1. JSON_ARRAYAGG:聚合为 JSON 数组

功能

将查询结果中的每一行的数据聚合成一个 JSON 数组。

语法
JSON_ARRAYAGG(expression)
  • expression: 要放入数组的值,可以是列、表达式或函数的返回值。

示例 1:简单使用

假设有一个表 employees

CREATE TABLE employees (
    id INT,
    name VARCHAR(50),
    department VARCHAR(50)
);

INSERT INTO employees VALUES 
(1, 'Alice', 'HR'),
(2, 'Bob', 'Engineering'),
(3, 'Charlie', 'HR');

我们希望将所有员工的姓名聚合成一个 JSON 数组:

SELECT JSON_ARRAYAGG(name) AS employee_names 
FROM employees;

结果

+----------------------+
| employee_names       |
+----------------------+
| ["Alice", "Bob", "Charlie"] |
+----------------------+

示例 2:按部门分组

将员工的姓名按部门聚合:

SELECT 
    department,
    JSON_ARRAYAGG(name) AS employee_names 
FROM employees
GROUP BY department;

结果

+-------------+--------------------+
| department  | employee_names     |
+-------------+--------------------+
| HR          | ["Alice", "Charlie"] |
| Engineering | ["Bob"]            |
+-------------+--------------------+

2. JSON_OBJECTAGG:聚合为 JSON 对象

功能

将查询结果中的每一行的两列数据聚合为键值对形式的 JSON 对象。

语法
JSON_OBJECTAGG(key_expression, value_expression)
  • key_expression: 对象的键。
  • value_expression: 对象的值。

示例 1:简单使用

继续使用 employees 表,我们希望创建一个以员工 ID 为键、姓名为值的 JSON 对象:

SELECT JSON_OBJECTAGG(id, name) AS employee_map 
FROM employees;

结果

+-------------------------------+
| employee_map                 |
+-------------------------------+
| {"1": "Alice", "2": "Bob", "3": "Charlie"} |
+-------------------------------+

示例 2:按部门分组

将每个部门的员工 ID 和姓名聚合为 JSON 对象:

SELECT 
    department,
    JSON_OBJECTAGG(id, name) AS employee_details 
FROM employees
GROUP BY department;

结果

+-------------+-----------------------------------+
| department  | employee_details                 |
+-------------+-----------------------------------+
| HR          | {"1": "Alice", "3": "Charlie"}   |
| Engineering | {"2": "Bob"}                     |
+-------------+-----------------------------------+

3. 比较与应用场景

函数输出格式适用场景
JSON_ARRAYAGGJSON 数组将多行数据组合成一个 JSON 数组,适用于无键值对的简单场景。
JSON_OBJECTAGGJSON 对象(键值对)生成键值对结构的 JSON 数据,例如主键-值映射或配置表等。

4. 结合使用的场景

假设我们有一个包含员工及其技能的表 employee_skills

CREATE TABLE employee_skills (
    employee_id INT,
    skill VARCHAR(50)
);

INSERT INTO employee_skills VALUES 
(1, 'Management'),
(1, 'Recruitment'),
(2, 'Java'),
(2, 'MySQL'),
(3, 'Communication');

我们希望为每个员工生成一个以员工 ID 为键、技能列表为值的 JSON 对象:

SELECT 
    JSON_OBJECTAGG(employee_id, skills) AS employee_skills_map
FROM (
    SELECT 
        employee_id,
        JSON_ARRAYAGG(skill) AS skills
    FROM employee_skills
    GROUP BY employee_id
) AS aggregated_skills;

结果

+-----------------------------------------+
| employee_skills_map                     |
+-----------------------------------------+
| {"1": ["Management", "Recruitment"],    |
|  "2": ["Java", "MySQL"],                |
|  "3": ["Communication"]}                |
+-----------------------------------------+

JSON_TABLE的使用

exp1:将数组中的每个对象元素转为一个关系表中的一行,表中的列对应了每个对象中的成员,其中for ordinality定义了自增长计数器列。

SELECT  * FROM  JSON_TABLE(
    '[{"x": 10, "y": 11}, {"x": 20, "y": 21}]','$[*]'   //表示数组中的所有元素
    COLUMNS (   id FOR ORDINALITY,
                x INT PATH '$.x',
                y INT PATH '$.y'  
            )    
        ) AS t;

exp2:提取数组中第2行,设置值为空时的缺省值

SELECT  * FROM  JSON_TABLE(  
    '[{"x": 10, "y": 11}, {"x": 20}]','$[1]'   //取数组中的第2个元素
            COLUMNS (  id FOR ORDINALITY,
            x INT PATH '$.x',
            y INT PATH '$.y'  DEFAULT '100' ON EMPTY 
            )    
        ) AS t;

exp3:拉平内嵌的数组

SELECT *  FROM  JSON_TABLE(   
    '[{"x":10,"y":[11, 12]},{"x":20,"y":[21, 22]}]',
        '$[*]'  COLUMNS (  
            x INT PATH '$.x',
            NESTED PATH '$.y[*]' COLUMNS (y INT PATH '$') 
         //展开 y 对应的数组,并将 y 数组中的每个元素放入名称为 y 的列中  
         )
) AS t;

res:
x     y
10    11
10    12
20    21
20    22

exp4:拉平内嵌的对象

SELECT  *   FROM   JSON_TABLE(    
    '[{"x":10,"y":{"a":11,"b":12}},{"x":20,"y":{"a":21,"b":22}}]',
        '$[*]'  COLUMNS (   x INT PATH '$.x',
            NESTED PATH '$.y' COLUMNS (   
                ya INT PATH '$.a',  
                yb INT PATH '$.b'  
                )          
            )
      ) AS t; 

res:
x   ya  yb
10  11  12
20  21  22

exp5:实际查询时应用

SELECT c1, c2, t.at, tt.bt, tt.ct, JSON_EXTRACT(c3, '$.*') 
FROM t1 AS m 
JOIN 
JSON_TABLE(   m.c3, 
  '$.*'  COLUMNS(
    at VARCHAR(10) PATH '$.a' DEFAULT '1' ON EMPTY, 
    bt VARCHAR(10) PATH '$.b' DEFAULT '2' ON EMPTY, 
    ct VARCHAR(10) PATH '$.c' DEFAULT '3' ON EMPTY
  )
) AS tt
ON m.c1 > tt.at;

例题:设MySQL数据库中有包含json数据列的关系R1(sno int, cno int , eval json)记录学生学习具体课程的学习记录的学号、课号、教师评语,完成下列小题:
(1)若要插入记录:1号学生学了3号课程,评语列的json对象由属性名“evaluation”和体教师评语的记录数组作为“evaluation”属性的值构成,该数组包含三条记录,分别是{ “stage”:1, “result”:”ok”}、{ “stage”:2, “result”:”good”}、{ “stage”:3, “result”:” excellent”},描述该生在该课程的3个阶段的教师评语。请写出MySQL中插入该记录的面向json拓展的SQL语句。

INSERT INTO R1 (sno, cno, eval) VALUES
 (1, 3, '{"evaluation":  [{"stage":1, "result":"ok"},
 {"stage":2, "result":"good"}, {"stage":3, "result":" excellent"}]  }');

(2)如果要在关系R1中查出上述第(1)小题插入的记录的前两个stage的信息,要求结果属性列表为“学号、课号、阶段号stage值及该阶段的教师评语result值”,并且不同的阶段输出在不同的行,请写出MySQL中插入该记录的面向json拓展的SQL语句。

因为记录只有一条,那么需要用where筛选时需要进行导出
SELECT sno,cno, tt.stage, tt.result FROM R1, 
JSON_TABLE (R1.eval,  '$.evauation[*]'   COLUMNS(
   stage int PATH '$.stage',
   result VARCHAR(20) PATH '$.result')
) AS tt  
WHERE tt.stage<3;

注释
SQL查询中,R1 表与 JSON_TABLE 函数生成的虚拟表 tt 之间看似没有进行显式的连接操作,但实际上,JSON_TABLE 函数本身就是一个连接点。JSON_TABLE 函数用于解析 JSON 格式的数据,并将解析出来的数据转换为关系表的形式,以便与 SQL 语句中的其他表进行联合查询。在这个过程中,JSON_TABLE 会自动将 R1 表中的每一行与 JSON 数据中的每一个元素进行关联,从而实现了隐式的连接。

让我们更详细地看看这个查询的各个部分:

  1. SELECT sno, cno, tt.stage, tt.result FROM R1,:

    • 这部分定义了查询的字段来源。snocno 来自 R1 表,而 tt.stagett.result 来自 JSON_TABLE 生成的虚拟表 tt
  2. JSON_TABLE (R1.eval, '$.evauation[*]' COLUMNS(stage int PATH '$.stage', result VARCHAR(20) PATH '$.result')) AS tt:

    • JSON_TABLE 函数接收两个参数:R1.eval 和一个 JSON 路径表达式 '$.evauation[*]'
    • R1.evalR1 表中的一个 JSON 字段,包含了需要解析的 JSON 数据。
    • '$.*evaluation[*]' 是一个 JSON 路径表达式,用于遍历 eval 字段中的 evaluation 数组中的每一个元素。
    • COLUMNS 子句定义了从每个 JSON 元素中提取的列及其路径。stageresult 分别对应 JSON 元素中的 stageresult 字段。
    • AS ttJSON_TABLE 函数生成的虚拟表命名为 tt
  3. WHERE tt.stage < 3:

    • 这个条件用于过滤 tt 表中的行,只保留 stage 值小于 3 的记录。

隐式连接的实现

尽管在 FROM 子句中没有显式地使用 JOIN 关键字,JSON_TABLE 函数实际上已经将 R1 表中的每一行与 eval 字段中的 JSON 数组中的每一个元素进行了关联。具体来说,JSON_TABLE 会为 R1 表中的每一行生成一个或多个虚拟行,每个虚拟行对应 eval 字段中的一个 JSON 元素。这些虚拟行与 R1 表中的原始行一起构成了最终的查询结果。

示例解释

假设 R1 表的数据如下:

snocnoeval
1101{“evaluation”: [{“stage”: 1, “result”: “pass”}, {“stage”: 2, “result”: “fail”}]}
2102{“evaluation”: [{“stage”: 1, “result”: “pass”}, {“stage”: 3, “result”: “pass”}]}

执行上述查询后,JSON_TABLE 会生成如下的虚拟表 tt

snocnostageresult
11011pass
11012fail
21021pass
21023pass

然后,WHERE tt.stage < 3 条件会过滤掉 stage 值为 3 的行,最终结果为:

snocnostageresult
11011pass
11012fail
21021pass

总结

虽然在 FROM 子句中没有显式的 JOIN 关键字,但 JSON_TABLE 函数实际上已经实现了 R1 表与 JSON 数据的隐式连接。这种连接方式使得可以从 JSON 格式的数据中提取结构化信息,并与表中的其他字段一起进行查询和过滤。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2249464.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一个开源轻量级的服务器资源监控平台,支持告警推送

大家好&#xff0c;今天给大家分享一款开源的轻量级服务器资源监控工具Beszel&#xff0c;提供历史数据记录、Docker容器统计信息监控以及多种警报功能&#xff0c;用于监控服务器资源。 项目介绍 Beszel由hub&#xff08;中心服务器端应用&#xff0c;基于PocketBase构建&…

使用Compose Multiplatform开发跨平台的Android调试工具

背景 最近对CMP跨平台很感兴趣&#xff0c;为了练手&#xff0c;在移动端做了一个Android和IOS共享UI和逻辑代码的天气软件&#xff0c;简单适配了一下双端的深浅主题切换&#xff0c;网络状态监测&#xff0c;刷新调用振动器接口。 做了两年多车机Android开发&#xff0c;偶…

[MRCTF2020]Transform

查壳&#xff0c;拖入64位IDA LOBYTE8位就是一个字节&#xff0c;在此处无意义&#xff0c;因为我们输入的本来就是按字节输入的 设 a byte_414040,bdword_40F040,cbyte_40F0E0,输入的字符串为flag; 从题目里得到 加密代码 a[i] flag[b[i]]; a[i] ^ b[i]; c a 即c[i] a[i…

podman 源码 5.3.1编译

1. 构建环境 在麒麟V10服务器操作系统上构建&#xff1a;Kylin-Server-V10-GFB-Release-2204-Build03-ARM64.iso。由于只是编译 podman 源码&#xff0c;没必要特地在物理机或服务上安装一个这样的操作系统&#xff0c;故采用在虚拟机里验证。 2. 安装依赖 参考资料&#xf…

Llmcad: Fast and scalable on-device large language model inference

题目&#xff1a;Llmcad: Fast and scalable on-device large language model inference 发表于2023.09 链接&#xff1a;https://arxiv.org/pdf/2309.04255 声称是第一篇speculative decoding边缘设备的论文&#xff08;不一定是绝对的第一篇&#xff09;&#xff0c;不开源…

用Java爬虫“搜刮”工厂数据:一场数据的寻宝之旅

引言&#xff1a;数据的宝藏 在这个数字化的时代&#xff0c;数据就像是隐藏在数字丛林中的宝藏&#xff0c;等待着勇敢的探险家去发掘。而我们&#xff0c;就是那些手持Java魔杖的现代海盗&#xff0c;准备用我们的爬虫船去征服那些数据的海洋。今天&#xff0c;我们将一起踏…

14、保存与加载PyTorch训练的模型和超参数

文章目录 1. state_dict2. 模型保存3. check_point4. 详细保存5. Docker6. 机器学习常用库 1. state_dict nn.Module 类是所有神经网络构建的基类&#xff0c;即自己构建一个深度神经网络也是需要继承自nn.Module类才行&#xff0c;并且nn.Module中的state_dict包含神经网络中…

【计算机网络】多路转接之poll

poll也是一种linux中的多路转接方案(poll也是只负责IO过程中的"等") 解决&#xff1a;1.select的fd有上限的问题&#xff1b;2.每次调用都要重新设置关心的fd 一、poll的使用 int poll(struct pollfd *fds, nfds_t nfds, int timeout); ① struct pollfd *fds&…

矩阵重新排列——sort函数

s o r t sort sort函数表示排序&#xff0c;对向量和矩阵都成立 向量 s o r t ( a ) sort(a) sort(a)将向量 a a a中元素从小到大排序 s o r t ( a , ′ d e s c e n d ′ ) sort(a,descend) sort(a,′descend′)将向量 a a a中元素从大到小排序 [ s o r t a , i d ] s o r…

深入解密 K 均值聚类:从理论基础到 Python 实践

1. 引言 在机器学习领域&#xff0c;聚类是一种无监督学习的技术&#xff0c;用于将数据集分组成若干个类别&#xff0c;使得同组数据之间具有更高的相似性。这种技术在各个领域都有广泛的应用&#xff0c;比如客户细分、图像压缩和市场分析等。聚类的目标是使得同类样本之间的…

Leetcode322.零钱兑换(HOT100)

链接 代码&#xff1a; class Solution { public:int coinChange(vector<int>& coins, int amount) {vector<int> dp(amount1,amount1);//要兑换amount元硬币&#xff0c;我们就算是全选择1元的硬币&#xff0c;也不过是amount个&#xff0c;所以初始化amoun…

【61-70期】Java面试题深度解析:从集合框架到线程安全的最佳实践

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Java &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 文章题目&#xff1a;Java面试题深度解析&#xff1a;从集合框架到线程安全的最佳实践 摘要&#xff1a; 本…

关闭AWS账号后,服务是否仍会继续运行?

在使用亚马逊网络服务&#xff08;AWS&#xff09;时&#xff0c;用户有时可能会考虑关闭自己的AWS账户。这可能是因为项目结束、费用过高&#xff0c;或是转向使用其他云服务平台。然而&#xff0c;许多人对关闭账户后的服务状态感到困惑&#xff0c;我们九河云和大家一起探讨…

JVM_垃圾收集器详解

1、 前言 JVM就是Java虚拟机&#xff0c;说白了就是为了屏蔽底层操作系统的不一致而设计出来的一个虚拟机&#xff0c;让用户更加专注上层&#xff0c;而不用在乎下层的一个产品。这就是JVM的跨平台&#xff0c;一次编译&#xff0c;到处运行。 而JVM中的核心功能其实就是自动…

若依框架部署在网站一个子目录下(/admin)问题(

部署在子目录下首先修改vue.config.js文件&#xff1a; 问题一&#xff1a;登陆之后跳转到了404页面问题&#xff0c;解决办法如下&#xff1a; src/router/index.js 把404页面直接变成了首页&#xff08;大佬有啥优雅的解决办法求告知&#xff09; 问题二&#xff1a;退出登录…

BERT解析

BERT项目 我在BERT添加注释和部分推理代码 main.py vocab WordVocab.load_vocab(args.vocab_path)#加载vocab那么这个加载的二进制是什么呢&#xff1f; 1. 加载数据集 继承关系&#xff1a;TorchVocab --> Vocab --> WordVocab TorchVocab 该类主要是定义了一个词…

连接共享打印机0X0000011B错误多种解决方法

打印机故障一直是一个热门话题&#xff0c;特别是共享打印机0x0000011b错误特别头疼&#xff0c;有很多网友经常遇到共享打印机0x0000011b错误。0x0000011b有更新补丁导致的、有访问共享打印机服务异常、有访问共享打印机驱动异常等问题导致的&#xff0c;针对共享打印机0x0000…

spring +fastjson 的 rce

前言 众所周知&#xff0c;spring 下是不可以上传 jsp 的木马来 rce 的&#xff0c;一般都是控制加载 class 或者 jar 包来 rce 的&#xff0c;我们的 fastjson 的高版本正好可以完成这些&#xff0c;这里来简单分析一手 环境搭建 <dependency><groupId>org.spr…

jeecgbootvue2重新整理数组数据或者添加合并数组并遍历背景图片或者背景颜色

想要实现处理后端返回数据并处理&#xff0c;添加已有静态数据并遍历快捷菜单背景图 遍历数组并使用代码 需要注意&#xff1a; 1、静态数组的图片url需要的格式为 require(../../assets/b.png) 2、设置遍历背景图的代码必须是: :style"{ background-image: url( item…

15分钟做完一个小程序,腾讯这个工具有点东西

我记得很久之前&#xff0c;我们都在讲什么低代码/无代码平台&#xff0c;这个概念很久了&#xff0c;但是&#xff0c;一直没有很好的落地&#xff0c;整体的效果也不算好。 自从去年 ChatGPT 这类大模型大火以来&#xff0c;各大科技公司也都推出了很多 AI 代码助手&#xff…