JSON_TABLE 两全其美

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 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 !

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
JSON 关系型数据库 MySQL
这个问题是由于Flink的Table API在处理MySQL数据时,将MULTISET类型的字段转换为了JSON格式
【1月更文挑战第17天】【1月更文挑战第84篇】这个问题是由于Flink的Table API在处理MySQL数据时,将MULTISET类型的字段转换为了JSON格式
241 1
|
JSON 前端开发 数据库
Bootstrap Table使用教程(请求json数据渲染表格)
Bootstrap Table使用教程(请求json数据渲染表格)
259 0
|
JSON 前端开发 数据格式
前端提升生产力系列二(vue3 element-plus 配置json快速生成table列表组件)
在PC端日常的使用中,使用最多的过于表单和列表了,故此对table列表和form表单进行了统一的封装,通过json配置就可以快速适配table列表和form表单。
680 0
前端提升生产力系列二(vue3 element-plus 配置json快速生成table列表组件)
|
JSON 关系型数据库 MySQL
Json 转 mysql create table
如果有大佬看到bug 或者可以优化的地方,可以帮忙指出来 不胜感激
368 0
|
XML JSON JavaScript
在JavaScript中用json对象创建一个table表格——实战练习
在JavaScript中用json对象创建一个table表格——实战练习
414 0
|
JSON C# 数据格式
C# Json处理日期和Table
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.
1051 1
|
JSON C# 数据库
C#无需第三方插件实现json和table互转
C# 数据库查询结果table转化为json字符串,或反向把json字符串转换为DataTable数据集合 以下代码经实践简单可用。 转换通用类定义: using System; using System.
3249 0
|
JSON 数据格式 JavaScript
jquery + json 动态创建复杂表格table
function SetSubTable() { var obj = jQuery.parseJSON($("#SubJsonStrValue").val()); window.
965 0
|
1月前
|
机器学习/深度学习 JSON 监控
淘宝拍立淘按图搜索与商品详情API的JSON数据返回详解
通过调用taobao.item.get接口,获取商品标题、价格、销量、SKU、图片、属性、促销信息等全量数据。
|
29天前
|
JSON 缓存 自然语言处理
多语言实时数据微店商品详情API:技术实现与JSON数据解析指南
通过以上技术实现与解析指南,开发者可高效构建支持多语言的实时商品详情系统,满足全球化电商场景需求。

热门文章

最新文章