使用 MySQL 转换 JSON 字段

Posted

技术标签:

【中文标题】使用 MySQL 转换 JSON 字段【英文标题】:Transform JSON field with MySQL 【发布时间】:2021-11-30 15:43:07 【问题描述】:

我在 tableA 中有一个 JSON 字段,我在其中保存一行从一种状态更改为另一种状态的时刻,就像这样,

row_id state_history
1 "2021-09-14 21:00": "State #4", "2021-09-16 21:00": "State #1", "2021-09-17 21:00": "State #6"
... ...

是否可以在 mysql 中使用这个 JSON 来生成一个表,在该表中我可以测量从一种状态变为另一种状态所需的时间?像这样:

row_id Initial_state Final_state Time_diff
1 State #4 State #1 2 days
1 State #1 State #6 1 day
2 State #5 State #2 1 day
2 State #2 State #1 4 days
2 State #1 State #6 1 day
... ... ... ...

请注意,每行的状态数会有所不同。 时差度量单位是分钟、小时还是天并不重要。

对于状态更改部分,我尝试了以下方法,但是这样我只能获得每行的第一个和第二个状态。我不知道如何制作时差部分。

SELECT A.row_id, A.state ->> '$[0]' AS Initial_state, A.state ->> '$[1]' AS Final_state
FROM 
(SELECT 
  row_id,
  state_history -> '$.*[0]' AS state
FROM 
  tableA) A

如果可能,按状态对(Initial_state、Final_state)进行分组,这样我就可以有一个指标来计算从特定状态变为另一个状态所需的平均时间。

【问题讨论】:

【参考方案1】:
WITH cte1 AS (
    SELECT test.row_id, 
           jsontable.`date`, 
           JSON_UNQUOTE(JSON_EXTRACT(test.state_history, CONCAT('$."', jsontable.`date`, '"'))) state
    FROM test
    CROSS JOIN JSON_TABLE(JSON_KEYS(state_history),
                          '$[*]' COLUMNS (`date` VARCHAR(64) PATH '$')) jsontable
),
cte2 AS (
    SELECT row_id, 
           LAG(state) OVER (PARTITION BY row_id ORDER BY `date`) Initial_state,
           state Final_state,
           DATEDIFF(`date`, LAG(`date`) OVER (PARTITION BY row_id ORDER BY `date`)) Time_diff,
           `date`
    FROM cte1
)
SELECT row_id,
       CAST(Initial_state AS CHAR) Initial_state,
       CAST(Final_state AS CHAR) Final_state,
       Time_diff
FROM cte2
WHERE Initial_state IS NOT NULL
ORDER BY row_id, `date`

step-by-step fiddle

【讨论】:

解决了问题,谢谢!

以上是关于使用 MySQL 转换 JSON 字段的主要内容,如果未能解决你的问题,请参考以下文章

查询Mysql表之后将结果转换为json时如何能够保持字段的原有数据类型?

将 JSON 字符串作为字段数据放在 MySQL 上

如何将数据从多个输入字段转换为单个 JSON 对象以进一步将其插入单个 mysql 字段

将 MySQL 结果转换为 JSON 的效率

mysql对json取值路径怎么设置变量

SQL解析Json字段