【问题标题】:How to select a field of a JSON object coming from the WHERE condition如何选择来自 WHERE 条件的 JSON 对象的字段
【发布时间】:2020-12-29 11:46:11
【问题描述】:

我有这张桌子

id  name   json
1   alex   {"type": "user", "items": [ {"name": "banana", "color": "yellow"}, {"name": "apple", "color": "red"} ] }
2   peter  {"type": "user", "items": [ {"name": "watermelon", "color": "green"}, {"name": "pepper", "color": "red"} ] }
3   john   {"type": "user", "items": [ {"name": "tomato", "color": "red"} ] }
4   carl   {"type": "user", "items": [ {"name": "orange", "color": "orange"}, {"name": "nut", "color": "brown"} ] }

重要的是,每个 json 对象可以有不同数量的“项目”,但我需要的是在 WHERE 条件下匹配的对象的“产品名称”。

我想要的输出是前两列和项目的名称,其中颜色类似于 %red%:

id name  fruit
1  alex  apple
2  peter pepper
3  john  tomato
select id, name, ***** (this is what I don't know) FROM table
where JSON_EXTRACT(json, "$.items[*].color") like  '%red%'

【问题讨论】:

  • 那个 JSON 有效吗?我不这么认为!不是必须的吗??我想是的!
  • 这不是有效的 JSON。 "items" 应该有方括号,而不是大括号。 "items: [ {"name": "banana", "color": "yellow"}, ... ].
  • 假设 JSON 在一个 JSON 值中包含 2 个带有红色的水果 - 在这种情况下您希望看到什么输出?
  • 您是如何创建插入数据库的 JSON 的?看来代码需要先修复
  • 对不起!我是在飞行中创建的......它是无效的,对不起,但这只是为了得到这个想法

标签: sql arrays json mariadb mariadb-10.5


【解决方案1】:

如果您运行的是 MySQL 8.0,我会推荐 json_table()

select t.id, t.name, x.name as fruit
from mytable t
cross join json_table(
    t.js,
    '$.items[*]' columns (name varchar(50) path '$.name', color varchar(50) path '$.color')
) x
where x.color = 'red'

这个功能在 MariaDB 中没有实现。我们可以在数字表的帮助下手动取消嵌套:

select t.id, t.name, 
    json_unquote(json_extract(t.js, concat('$.items[', x.num, '].name'))) as fruit
from mytable t
inner join (select 0 as num union all select 1 union all select 2 ...) x(num)
    on x.num < json_length(t.js, '$.items')
where json_unquote(json_extract(t.js, concat('$.items[', x.num, '].color'))) = 'red'

【讨论】:

  • 我正在运行 MariaDb 10.5 ...但我认为它不起作用:-(
  • @FlamingMoe:啊,好吧...您最初标记了您的问题 MySQL(有一个单独的 MariaDB 标签),因此我的回答。请参阅我对 MariaDB 兼容解决方案的编辑。
【解决方案2】:

您可以使用JSON_EXTRACT() 函数和Recursive Common Table Expression 来动态生成行,例如

WITH RECURSIVE cte AS 
(
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1
    FROM cte
   WHERE cte.n < (SELECT MAX(JSON_LENGTH(json)) FROM t )
)
SELECT id, name, 
       JSON_UNQUOTE(JSON_EXTRACT(json,CONCAT('$.items[',n-1,'].name'))) AS fruit
  FROM cte
  JOIN t
 WHERE JSON_EXTRACT(json,CONCAT('$.items[',n-1,'].color')) = "red"

Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-27
    • 1970-01-01
    • 2018-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多