mysql - 如何在 MySQL 中使用 JSON 文档加入子查询?

标签 mysql sql json mysql-8.0

Mysql版本为8.0.18-commercial。表的主键是 id。 我编写了以下查询,它显示 hostnamedetails

select hostname, details from table t1;

hostname: abc123
details:
[
  {
    "Msg": "Job Running",
    "currentTask": "IN_PROGRESS",
    "activityDate": "2020-07-20 16:25:15"
  },
  {
    "Msg": "Job failed",
    "currentTask": "IN_PROGRESS",
    "activityDate": "2020-07-20 16:35:24"
  }
]

我只想从具有最新 activityDate 的元素中获取 Msg

我想要的输出显示 hostname 以及具有 latest date 的元素的 Msg :

hostname        Msg
abc123          Job failed

我编写了以下查询,它运行成功但根本不显示任何内容。此外,它需要 17secs 来执行。

select hostname,
(select Msg
from (
    select x.*, row_number() over(partition by t.id order by x.activityDate) rn
    from table1 t
    cross join json_table(
        t.audits,
        '$[*]' columns(
            Msg varchar(50) path '$.Msg',
            activityDate datetime path '$.activityDate'
        )
    ) x
) t
where rn = 1) AS Msg
from table1;

最佳答案

  • 您需要通过删除末尾的逗号来修复 JSON 的格式 以 "activityDate" keys
  • 开头的行数
  • 转换函数如 STR_TO_DATE() 应该应用于 派生的 activityDate 列以获得订购日期(不是 characterwise) 结果。
  • 通过ROW_NUMBER() 解析不需要子查询 ORDER BY 子句旁边的函数(with descending order ),并添加一个 LIMIT 1 子句 在查询结束时

因此,您可以将查询重写为

SELECT t1.hostname,
       j.Msg
  FROM t1
 CROSS JOIN
     JSON_TABLE(details, '$[*]' 
       COLUMNS (

                Msg VARCHAR(100)  PATH '$.Msg',
                activityDate VARCHAR(100)  PATH '$.activityDate'                        
               )
     ) j 
 ORDER BY ROW_NUMBER() 
          OVER ( -- PARTITION BY id 
                ORDER BY STR_TO_DATE(j.activityDate, '%Y-%m-%d %H:%i:%S') DESC)    
 LIMIT 1   

Demo

更新:

对于有多个 id 值的情况,您可以考虑在子查询中使用 ROW_NUMBER() 函数,并在主查询中过滤掉返回等于 1 的值:

SELECT id, Msg
  FROM
  (
   SELECT t1.*, j.Msg,
          ROW_NUMBER() 
          OVER (PARTITION BY id 
                ORDER BY STR_TO_DATE(j.activityDate, '%Y-%m-%d %H:%i:%S') DESC) AS rn   
     FROM t1
    CROSS JOIN
          JSON_TABLE(details, '$[*]' 
          COLUMNS (    
                   Msg VARCHAR(100)  PATH '$.Msg',
                   activityDate VARCHAR(100)  PATH '$.activityDate'                        
                  )
     ) j 
   ) q
 WHERE rn= 1

Demo

另一种方法使用 ROW_NUMBER() 函数和 LIMIT 子句包含相关子查询,并且适用于具有多个 id 值的记录:

SELECT t.id, 
 ( SELECT j.Msg
     FROM t1
    CROSS JOIN
        JSON_TABLE(details, '$[*]' 
        COLUMNS (
                Msg VARCHAR(100)  PATH '$.Msg',
                activityDate VARCHAR(100)  PATH '$.activityDate'                        
                )
        ) j
     WHERE t1.id = t.id  
     ORDER BY ROW_NUMBER() 
              OVER (ORDER BY STR_TO_DATE(j.activityDate, '%Y-%m-%d %H:%i:%S') DESC)    
     LIMIT 1 ) AS Msg
  FROM t1 AS t

Demo

关于mysql - 如何在 MySQL 中使用 JSON 文档加入子查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63006218/

相关文章:

json - MongoExport 有效的 JSON 查询构造

mysql - 如何与实体经理一起加入 Doctrine ?

mysql - 写锁定mysql中的所有表片刻

mysql - 设置用于在家中托管 Java EE 应用程序的服务器

mysql - 从第二个表返回类别(如果存在)

SQL查询将1列划分为3列

json - 如何将 ElasticSearch 快照从存储库下载到本地计算机?

mysql - 获取以下查询的答案的计数

mysql - 从另一个表中使用 SELECT 插入 SQL

java - 使用动态根名称反序列化 JSON