【问题标题】:How to select from MySQL JSON array as rows? [duplicate]如何从 MySQL JSON 数组中选择行? [复制]
【发布时间】:2021-02-10 22:05:35
【问题描述】:

使用 MySQL 5.7,如何从 JSON 列中选择数组元素作为行?

Person

id      data
1       [{"name":"one"},{"name":"two"}]
2       [{"name":"three"},{"name":"four"}]

我想将 JSON 数组中的元素“旋转”到行。 不工作下面的 SQL...

SELECT
    p.id AS personId,
    d->'$.name' AS name
FROM
    Person p
    JSON_EXTRACT(p.data) d  # <-- not valid SQL
WHERE
    d->'$.name' <> 'three'

预期输出

personId  name
1         one
1         two
2         four

【问题讨论】:

  • 在 MySQL 8.0 中使用 JSON_TABLE() 的唯一合理方法,因此您应该升级。另一种方法是将数据存储在正常的行和列中。无论如何,我建议您避免使用 JSON,因为您需要在 JSON 字段中搜索特定值。我建议仅在选择列表中引用 JSON 字段,不要在查询的其他子句中引用。
  • 这是一个现有的数据库(此处未显示)。我们不在 SQL 查询中使用 JSON 数据,这是出于数据恢复的目的,这有助于根据 JSON blob 中的某些值缩小我们的修复范围。除此之外,它没有被数据库触及。是的,升级到 MySQL 8 会很好......

标签: mysql sql arrays json unnest


【解决方案1】:

如果你运行的是 MySQL 8.0,你可以使用json_table():

select p.id, x.name
from person p
cross join json_table(
    p.data,
    '$[*]' columns (name varchar(50) path '$.name')
) x
where x.name <> 'three'

在早期版本中,一种替代方法是使用派生的数字表来取消嵌套数组:

select *
from (
    select p.id, json_unquote(json_extract(p.data, concat('$[', n.num, '].name'))) name
    from person p
    inner join (select 0 num union all select 1 union all select 2) n
        on n.num < json_length(p.data)
) t
where name <> 'three'

union all 子查询应包含至少与表的任何 JSON 数组中的最大元素数一样多的元素。

DB Fiddle 上的演示:

【讨论】:

  • 如果他想处理一个有四个元素的 JSON 数组怎么办?您必须更改查询?原谅我,但这不是一个合理的解决方案。我想这是展示它的重点。
  • @BillKarwin:这个想法是拥有一个包含足够多元素的数字表,因此无需担心以后修改查询。如您所知,有一些相对简单的方法可以生成非常大的数字表。也就是说,我同意你的观点,最好将数据存储在标准化结构中(为什么顺便删除你的答案?我发现它与我的非常互补)。
  • 我意识到这个问题是重复的,并投票关闭它。我觉得自己发布答案然后投票结束问题,阻止其他人回答是不好的形式。但我会添加一条相同效果的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-02
  • 1970-01-01
  • 2017-12-04
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多