【问题标题】:convert all JSON columns into new table将所有 JSON 列转换为新表
【发布时间】:2018-08-21 01:02:12
【问题描述】:

我目前的表格结构如下:

customer_id  name   phoneNumbers  
1            Adam   [{'type':'home','number':'687-5309'} , {'type':'cell','number':'123-4567'}] 
2            Bill   [{'type':'home','number':'987-6543'}] 

将 phoneNumbers 列设置为 JSON 列类型。 为简单起见,虽然我想将所有 JSON 电话号码转换为一个新的单独表。 比如:

phone_id  customer_id type    number
1         1           home    687-5309  
2         1           cell    123-4567
3         2           home    987-6543

似乎应该可以使用 OPENJSON,但到目前为止,我还没有弄清楚如何正确声明它的运气。任何帮助表示赞赏。

【问题讨论】:

  • OPENJSON 是 Microsoft SQL Server 中的一个函数,但您将问题标记为 mysql。您使用的是哪个数据库品牌?
  • 我正在使用 MariaDB 。我没有意识到 OPENJSON 是 Microsoft SQL Server 独有的。有 MariaDB 替代品吗?
  • 我不使用 MariaDB。通过查看他们的文档,您的问题似乎很容易回答。

标签: mysql sql json json-query


【解决方案1】:

使用 1 的递归 CTE 并递归到 json_length。

SELECT c.*, JSON_LENGTH(c.phoneNumbers) as json_length
from customers c;

然后使用 concat 在 Extract Query 中传递该 element_id:

(json_unquote(JSON_EXTRACT(phoneNumbers, CONCAT('$.type.',1))), json_unquote(JSON_EXTRACT(phoneNumbers, CONCAT('$.number.',1))))
(json_unquote(JSON_EXTRACT(phoneNumbers, CONCAT('$.type.',2))), json_unquote(JSON_EXTRACT(phoneNumbers, CONCAT('$.number.',1))))
-
-
-
(json_unquote(JSON_EXTRACT(phoneNumbers, CONCAT('$.type.',json_length))), json_unquote(JSON_EXTRACT(phoneNumbers, CONCAT('$.number.',json_length))))

【讨论】:

  • 直到现在我才听说过 CTE,但它看起来确实可行。但我不确定我是否遵循您发布的代码。我在这里创建了一个 dbfiddle,据我所知:dbfiddle.uk/…
  • 是的,我想是的。我在路障。您可以提供的任何其他帮助都会很棒。
  • 请获取最新答案。
【解决方案2】:

你可以这样做:

SELECT id,
    name,
    JSON_UNQUOTE(JSON_EXTRACT(phone, CONCAT("$[", seq.i, "]", ".", "number"))) AS NUMBER, 
    JSON_UNQUOTE(JSON_EXTRACT(phone, CONCAT("$[", seq.i, "]", ".", "type"))) AS TYPE
FROM customer, (SELECT 0 AS I UNION ALL SELECT 1) AS seq
WHERE seq.i < json_length(phone)

诀窍是(SELECT 0 as i union all SELECT 1),取决于您的 JSON 数组的长度,您可能需要添加更多索引。您可以通过以下方式找出最大长度:

SELECT MAX(JSON_LENGTH(phone)) FROM customer;

【讨论】:

  • 看起来很棒。我将对其进行分解以弄清楚它是如何工作的。谢谢你的例子。
  • 实际上在玩了一会儿之后,它似乎不太有效(或者我无法让它工作)。我扩大了数字以包括 1 个,但它仍然只选择 3 个结果(应该是 4 个)。 dbfiddle:dbfiddle.uk/…
  • 对不起,我没有把自己说清楚。你需要添加更多的union all select index来匹配数组的长度,应该是:dbfiddle.uk/…
  • 明白了。这更有意义,但是如果我有 200 个(夸张的)电话号码,我会继续将 UNION ALL 添加到查询中。我知道你在获得最大长度之前提到过。这种查询有可能吗?我能够在这里得到一些工作:dbfiddle.uk/… 但它似乎不正确。
【解决方案3】:

请根据 MySQL\Maria 版本更改 CTE 定义语法。

WITH RECURSIVE cte_recurse_json AS
(
  SELECT customer_id, phone_numbers, 0 as recurse, JSON_LENGTH(c.phoneNumbers) as json_length, 
            json_unquote(JSON_EXTRACT(phoneNumbers, CONCAT('$[',0,'].type'))) as type, 
            json_unquote(JSON_EXTRACT(phoneNumbers, CONCAT('$[',0,'].number'))) as number
  FROM table
  UNION ALL
  SELECT t.customer_id, t.phone_numbers, ct.recurse + 1 as recurse, t.json_length, 
            json_unquote(JSON_EXTRACT(ct.phoneNumbers, CONCAT('$[',ct.recurse,'].type'))) as type, 
            json_unquote(JSON_EXTRACT(ct.phoneNumbers, CONCAT('$[',ct.recurse,'].number'))) as number
  FROM TABLE t
  INNER JOIN cte_recurse_json ct ON t.customer_id = ct.customer_id
  WHERE ct.recurse < json_length
)
SELECT customer_id, type, number FROM cte_recurse_json;

【讨论】:

    猜你喜欢
    • 2020-01-20
    • 2022-10-23
    • 2021-08-27
    • 2019-07-26
    • 2018-06-22
    • 2012-08-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多