【问题标题】:Converting multivalued column in table A to multiple rows in table B Mysql将表A中的多值列转换为表B中的多行Mysql
【发布时间】:2021-10-21 14:03:30
【问题描述】:

给定 2 个表,我想转换表 1 中的多值行

给定 2 张桌子 表A

id  value
ae  [1,2,4,5]
ac  [1,6]

表 B

id  value
ae   1
ae   2
ae   4
ae   5
ac   1
ac   6

我知道我必须在表 B 上插入一个前插入触发器,但我无法弄清楚逻辑。

【问题讨论】:

  • 你有mysql 8吗?然后查找 json_table,否则您可以查找 splittng stings
  • 表 A 中的列 value 的数据类型是什么?什么是 MySQL 版本?
  • mysql8,值为varchar

标签: mysql mysql-workbench


【解决方案1】:

另一种将 MySQL 中的 JSON 数组转换为行的方法(我假设表 A 中的“值”列是 json 数组类型)。将表 A 转换为表 B。

MySql >= 8.0:

首先使用递归查询,我为每个长度 > 0(每个索引一行)的 json 数组获取 json 数组索引,然后我将表 A 与索引查询连接起来,并使用 JSON_EXTRACT() 提取每个 json 数组值行。

WITH RECURSIVE indexes AS (SELECT id, 0 AS json_index FROM A WHERE JSON_LENGTH(value) > 0
                          
                        UNION ALL
                        
                        SELECT i.id, i.json_index + 1
                        FROM indexes i
                        INNER JOIN A ON A.id = i.id AND i.json_index < JSON_LENGTH(A.value) - 1
                        )
                        
SELECT A.id, JSON_EXTRACT(A.value, CONCAT('$[', i.json_index, ']')) AS arrayValue
FROM A
INNER JOIN indexes i ON A.id = i.id;

【讨论】:

    【解决方案2】:

    这是一个想法:

    获取需要使用LENGTH()分隔的总价值:

    以第一个例子[1,2,4,5]为例。这里有 4 个用逗号分隔的值。如果我们做LENGTH(value),我们将得到9,因为有9个字符,包括[,。然后我们执行LENGTH(REPLACE(value,',','')),我们将值中的逗号替换为空,这将给我们6。如果我们减去它们,我们将得到3,我们假设得到4,所以我们在最终计算中加上+1。我们最终会得到这样的结果:

    (LENGTH(value)-LENGTH(REPLACE(value, ',', '' )))+1
    

    这样,您将获得ae4ac2。从这里有此信息的三种用途:

    1. 根据我们得到的最大数字来创建一个编号序列,在本例中为4
    2. 根据value 列的长度返回重复的行。
    3. 用于SUBSTRING_INDEX()函数并相应返回值。

    最后,我设法使用相同的想法创建了两个查询,但使用了不同的 MySQL 版本。

    对于较旧的 MySQL 版本(v8 之前),可能会这样做:

    SELECT id,
           SUBSTRING_INDEX(SUBSTRING_INDEX(val,',',ln),',',-1) AS value
     FROM
    (SELECT 1 AS ln UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) RN
    LEFT JOIN
    (SELECT id, 
            REPLACE(REPLACE(value,'[',''),']','') AS val 
       FROM tableA) A
    ON ln<=(LENGTH(val)-LENGTH(REPLACE(val,',','')))+1
    ORDER BY id, value;
    

    但是,这里的问题是查询..(SELECT 1 AS ln UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) RN.. 的这一部分上的硬编码编号顺序。这意味着如果有一个value的长度是不断变化的,那么这部分需要不断地编辑。

    对于 MySQL v8(但不完全支持 JSON_TABLE 的 v8.0.4):

    WITH RECURSIVE cte AS (
    SELECT 1 AS ln, MAX((length(value)-length(replace(value,',','')))+1) AS totval
    from tableA UNION ALL
    SELECT ln+1, totval FROM cte WHERE ln+1 <= totval)
    SELECT id, 
           REGEXP_REPLACE(SUBSTRING_INDEX(SUBSTRING_INDEX(value,',',ln),',',-1),'[^0-9]','') AS value
    FROM cte 
    LEFT JOIN tableA
    ON ln<=(length(value)-length(replace(value,',','')))+1
    ORDER BY id, value;
    

    这里我使用WITH RECURSIVE函数来动态生成编号序列,也就是说如果长度大于4,则不需要编辑查询。

    Demo fiddle

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      • 2020-07-08
      • 2013-06-25
      • 1970-01-01
      • 1970-01-01
      • 2018-09-14
      • 2020-07-15
      相关资源
      最近更新 更多