如何在mysql中使用json文档连接子查询?

3xiyfsfu  于 2021-07-24  发布在  Java
关注(0)|答案(2)|浏览(372)

mysql版本是 8.0.18-commercial . 表的主键是 id . 我编写了以下查询,其中显示 hostname 以及 details

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"
  }
]

我想要那个 Msg 值仅来自具有最新 activityDate 我想要的输出正在显示 hostname 伴随着 Msg 元素的 latest date :

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;
bjg7j2ky

bjg7j2ky1#

您需要通过删除以开头的行末尾的逗号来修复json的格式 "activityDate" 钥匙
转换函数,如 STR_TO_DATE() 应应用于派生的 activityDate 列以获取按日期排序(而不是按字符排序)的结果。
通过puting不需要子查询 ROW_NUMBER() 函数旁边的分析函数 ORDER BY 子句(按降序),并添加 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

演示
更新:
对于具有多个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

演示
另一种方法使用 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

演示

uurity8g

uurity8g2#

也许我是老派,但是日期字段应该作为一个单独的字段存储在json之外,以便于查询。
id是否自动递增,数据是否按时间戳顺序插入?如果是,则可以运行如下查询,为每个主机名提供最后一行:

SELECT id, hostname, details 
FROM table t1
WHERE NOT EXISTS (SELECT 1 FROM table t2 WHERE t2.hostname = t1.hostname AND t2.id > t1.id) ;

相关问题