拆分具有多个值的单个VARCHAR字段,并单独插入它们

时间:2014-09-30 20:58:29

标签: mysql sql

我正在将旧数据库数据迁移到新数据库,他们过去常常按以下格式存储电话号码:

示例1:

41.9044-9082;41.9044-9661;41.9851-9862;41.9984-0393;41.3399-9169;41.3997-7999;

示例2:

41.3369-0102;41.8928-5992;

没有电话(空):

;

如何将这些单个VARCHAR字段拆分为多个值,并单独插入?

表格示例:

|#id_tel#|### number ####|#|client_id|#|
|#  1   #|111163;3554353;|#|   2     |#|
|#  2   #|222222;        |#|   3     |#|
|#  3   #|;              |#|   4     |#|

表示我希望如何:

|#id_tel#|### number ####|#|client_id|#|
|#  1   #|111163         |#|   2     |#|
|#  2   #|3554353        |#|   2     |#|
|#  3   #|222222         |#|   3     |#|

1 个答案:

答案 0 :(得分:1)

您可以使用SUBSTRING_INDEX()和数字表的嵌套调用来实现。在我的例子中,我动态创建了数字表,最多可以有100个数字。

假设表old_tel具有以下CREATE TABLE语句:

CREATE TABLE old_tel (
    id_tel INT,
    `number` VARCHAR(200),
    client_id INT
);

使用此查询获取带有client_id的拆分数字:

  SELECT
      SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1) value,
      client_id
  FROM 
      old_tel
  CROSS JOIN (
      SELECT 
          1 + a.N + b.N * 10 AS n
      FROM
          (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
          ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
      ORDER BY n      
  ) n
  WHERE
      n.n <= LENGTH(`number`) - LENGTH(REPLACE(`number`, ';', ''))
  AND
      SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1) <> ''
  ORDER BY
     client_id, SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1);

假设您的新电话号码表看起来几乎相同:

CREATE TABLE new_tel (
    id_tel INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `number` VARCHAR(200),
    client_id INT
);

您可以使用第一个查询使用这个简单的INSERT语句填充此表:

  INSERT INTO new_tel (`number`, client_id)
  SELECT
      SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1) value,
      client_id
  FROM 
      old_tel
  CROSS JOIN (
    SELECT 
        1 + a.N + b.N * 10 AS n
    FROM
        (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
        ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
    ORDER BY n    
  ) n
  WHERE
    n.n <= LENGTH(`number`) - LENGTH(REPLACE(`number`, ';', ''))
  AND
    SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1) <> ''
  ORDER BY
     client_id, SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1);

解释

带有UNION ALL的内部子选择动态创建数字表。我们将此限制在number列中的子字符串数量,并过滤掉空值。

SUBSTRING_INDEX(SUBSTRING_INDEX(`number`, ';', n.n), ';', -1) value

删除以分号分隔的第n个数字。

看到它在 Demo

中工作

**注意:**通过避免逐行插入令人痛苦,这是非常快的。