JSON_TABLE 两全其美

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 在这篇博客文章中,我将向您展示如何做到这一点,并讨论JSON_TABLE如何启用使用SQL处理JSON数据的新方法。

MySQL 8.0中的一个新的JSON函数是JSON_TABLE。它也是MySQL的第一个表函数。也就是说,返回值不是标量值而是结果集。JSON_TABLE将JSON文档(部分)转换为关系表。在这篇博客文章中,我将向您展示如何做到这一点,并讨论JSON_TABLE如何启用使用SQL处理JSON数据的新方法。

JSON_TABLE例子

首先,我将创建一个表t1,其中的一列为JSON类型,并向表中插入一个JSON文档:

CREATE TABLE t1(json_col JSON);
 
INSERT INTO t1 VALUES (
    '{ "people": [
        { "name":"John Smith",  "address":"780 Mission St, San Francisco, CA 94103"}, 
        { "name":"Sally Brown",  "address":"75 37th Ave S, St Cloud, MN 94103"}, 
        { "name":"John Johnson",  "address":"1262 Roosevelt Trail, Raymond, ME 04071"}
     ] }'
);

我可以使用以下SQL查询转换为关系表的文件:

SELECT people.* 
FROM t1, 
     JSON_TABLE(json_col, '$.people[*]' COLUMNS (
                name VARCHAR(40)  PATH '$.name',
                address VARCHAR(100) PATH '$.address')
     ) people;

因为JSON_TABLE返回一个结果集,所以可以在FROM子句中使用它。JSON_TABLE接受以下参数:

  • 1.JSON数据源:这个表达式可以引用FROM列表中前面表中的列。在本例中,json_col指的是包含JSON文档的列。(注意,按照SQL标准的规定,前面的表和引用该表的JSON_TABLE之间有一个隐式的横向连接(lateral join)。换句话说,对于前面的表的每一行,将“调用”JSON_TABLE函数。)
  • 2.应该转换为表的JSON数组的路径。在本例中,它是people数组的对象。
  • 3.那些表中的列,其列名、类型和路径应该在JSON对象中可以找到值。

我们还需要给返回的表一个名称,这里我们称它为people。

以上查询将返回以下结果:

NAME ADDRESS
John Smith 780 Mission St, San Francisco, CA 94103
Sally Brown 75 37th Ave S, St Cloud, MN 9410
John Johnson 1262 Roosevelt Trail, Raymond, ME 04071

对JSON文档的关系操作

当我们使用JSON_TABLE将JSON文档转换为表时,我们可以使用“SQL工具集”并对数据执行诸如选择和聚合之类的关系操作。例如,我们可以使用这个查询来选择只叫John的人:

SELECT people.* 
FROM t1, 
     JSON_TABLE(json_col, '$.people[*]' COLUMNS (
                name VARCHAR(40)  PATH '$.name',
                address VARCHAR(100) PATH '$.address')
     ) people;
WHERE people.name LIKE 'John%';
NAME ADDRESS
John Smith 780 Mission St, San Francisco, CA 94103
John Johnson 1262 Roosevelt Trail, Raymond, ME 04071

另一个MySQL 8.0中的新函数JSON_ARRAYAGG,我们现在可以将结果转换回JSON文档:

SELECT JSON_OBJECT("people", 
       JSON_ARRAYAGG(JSON_OBJECT("name", name, "address", address))) json_doc
FROM t1, 
     JSON_TABLE(json_col, '$.people[*]' COLUMNS (
                name VARCHAR(40)  PATH '$.name',
                address VARCHAR(100) PATH '$.address')
     ) people;
WHERE people.name LIKE 'John%';

JSON文档

{"people": [{"name": "John Smith", "address": "780 Mission St, San Francisco, CA 94103"}, {"name": "John Johnson", "address": "1262 Roosevelt Trail, Raymond, ME 04071"}]}

如上所示,我们可以通过JSON_TABLE和JSON_ARRAYAGG对JSON文档执行关系操作。

嵌套的JSON数组

JSON_TABLE还可以处理嵌套JSON数组。给定以下JSON数组与家族对象,有数组与子对象:

[
  {
    "father": "John",
    "mother": "Mary",
    "children": [
      {
        "age": 12,
        "name": "Eric"
      },
      {
        "age": 10,
        "name": "Beth"
      }
    ],
    "marriage_date": "2003-12-05"
  },
  {
    "father": "Paul",
    "mother": "Laura",
    "children": [
      {
        "age": 9,
        "name": "Sarah"
      },
      {
        "age": 3,
        "name": "Noah"
      },
      {
        "age": 1,
        "name": "Peter"
      }
    ]
  }
]

我们想要将这个文档转换为每个子元素对应一行的表:

ID FATHER MARRIED CHILD_ID CHILD AGE
1 John 1 1 Eric 12
1 John 1 2 Beth 10
2 Paul 0 1 Sarah 9
2 Paul 0 2 Noah 3
2 Paul 0 3 Peter 1
JSON_TABLE (families, '$[*]' COLUMNS (    
            id FOR ORDINALITY,
            father VARCHAR(30) PATH '$.father',
            married INTEGER EXISTS PATH '$.marriage_date',
            NESTED PATH '$.children[*]' COLUMNS (
              child_id FOR ORDINALITY,
              child VARCHAR(30) PATH '$.name',
              age INTEGER PATH '$.age') )    
)

我们使用嵌套路径来指定应该从子数组中提取哪些值。这个示例还表明,我们可以通过指定序数而不是路径来为行分配id。我们还可以使用EXISTS PATH检查路径是否存在。这里,如果找到结婚日期,则married为1,否则为0。

对JSON数据进行SQL聚合

一旦我们使用JSON_TABLE将JSON数据转换为关系表,我们就可以利用SQL聚合来计算JSON数据的计数、总和、平均值等。使用上面提供的例子,这个查询将计算每个家庭孩子的平均年龄:

SELECT father, COUNT(*) "#children", AVG(age) "age average"
FROM t,
     JSON_TABLE (families, '$[*]' COLUMNS (
                 id FOR ORDINALITY,
                 father VARCHAR(30) PATH '$.father',
                 NESTED PATH '$.children[*]' COLUMNS (
                    age INTEGER PATH '$.age' ) ) 
     ) fam
GROUP BY id, father; 
ATHER#CHILDREN AGE AVERAGE
John 2 11.0000
Paul 3 4.3333

我们甚至可以使用JSON_MERGE_PATCH函数将计算出来的数据放回JSON文档中:

SELECT JSON_ARRAYAGG(fam_obj) families
FROM (
  SELECT JSON_MERGE_PATCH(family,
           JSON_OBJECT("#children", COUNT(*), "avg_age" , AVG(age))) fam_obj
  FROM t, 
       JSON_TABLE (families, '$[*]' COLUMNS (
                   id FOR ORDINALITY,
                   family JSON PATH '$',
                   NESTED PATH '$.children[*]' COLUMNS (
                     age INTEGER PATH '$.age' ) ) 
       ) fam
   GROUP BY id, family) fams;

这里,我们将现有的family对象与计算后的总和和平均值构造的对象合并。然后,JSON_ARRAYAGG将把所有合并的对象放回一个数组中。

结论

在这篇博客文章中,我展示了如何使用JSON_TABLE对JSON数据执行关系操作。使用JSON_ARRAYAGG,您可以采取相反的做法,将结果集转换为JSON文档。这能让你两全其美;您可以将数据存储为JSON格式,但同时也可以利用SQL的强大功能。

感谢您使用MySQL !

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
4月前
|
JSON 关系型数据库 MySQL
这个问题是由于Flink的Table API在处理MySQL数据时,将MULTISET类型的字段转换为了JSON格式
【1月更文挑战第17天】【1月更文挑战第84篇】这个问题是由于Flink的Table API在处理MySQL数据时,将MULTISET类型的字段转换为了JSON格式
81 1
|
10月前
|
JSON 前端开发 数据库
Bootstrap Table使用教程(请求json数据渲染表格)
Bootstrap Table使用教程(请求json数据渲染表格)
126 0
|
JSON 关系型数据库 MySQL
Json 转 mysql create table
如果有大佬看到bug 或者可以优化的地方,可以帮忙指出来 不胜感激
218 0
|
XML JSON JavaScript
在JavaScript中用json对象创建一个table表格——实战练习
在JavaScript中用json对象创建一个table表格——实战练习
246 0
|
JSON 前端开发 数据格式
前端提升生产力系列二(vue3 element-plus 配置json快速生成table列表组件)
在PC端日常的使用中,使用最多的过于表单和列表了,故此对table列表和form表单进行了统一的封装,通过json配置就可以快速适配table列表和form表单。
487 0
前端提升生产力系列二(vue3 element-plus 配置json快速生成table列表组件)
|
JSON C# 数据库
C#无需第三方插件实现json和table互转
C# 数据库查询结果table转化为json字符串,或反向把json字符串转换为DataTable数据集合 以下代码经实践简单可用。 转换通用类定义: using System; using System.
3152 0
|
JSON C# 数据格式
C# Json处理日期和Table
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.
990 0
|
JSON 数据格式 JavaScript
jquery + json 动态创建复杂表格table
function SetSubTable() { var obj = jQuery.parseJSON($("#SubJsonStrValue").val()); window.
901 0
|
3天前
|
XML 存储 JSON
Twaver-HTML5基础学习(19)数据容器(2)_数据序列化_XML、Json
本文介绍了Twaver HTML5中的数据序列化,包括XML和JSON格式的序列化与反序列化方法。文章通过示例代码展示了如何将DataBox中的数据序列化为XML和JSON字符串,以及如何从这些字符串中反序列化数据,重建DataBox中的对象。此外,还提到了用户自定义属性的序列化注册方法。
18 1
|
4天前
|
JSON JavaScript 数据格式
vue写入json数据到文本中+vue引入cdn的用法
vue写入json数据到文本中+vue引入cdn的用法