【问题标题】:MySQL Converting Database Column From Blob to separate piecesMySQL将数据库列从Blob转换为单独的部分
【发布时间】:2013-09-11 19:28:01
【问题描述】:

我正在尝试从旧的 MySQL 表中取出一个 blob 并为其创建一个新表,以达到第一个正常形式。然而,将数据库中已有的数据从 blob 转换为新表中的多行并非易事。

用SQL命令实现转换最简单的方法是什么?

父表:

CREATE  TABLE TEST.People (
  `id` INT  AUTO_INCREMENT,
  `age` INT,
  `height` INT,
  `weight` INT  ,
  `variations` BLOB DEFAULT NULL,
  PRIMARY KEY (`id`), 
);

新表:

CREATE  TABLE TEST.Variations (
  `id` INT  AUTO_INCREMENT,
  `chr` INT,
  `start` INT,
  `stop` INT  ,
  `type` ENUM('SNP','INDEL','CNV') DEFAULT NULL,
  PRIMARY KEY (`id`), 
);

当我运行 SELECT id,variations FROM TEST.People; 我明白了:

+----+----------------------------------------------------------------------------------------------------------------------+
| id | variations                                                                                                           |
+----+----------------------------------------------------------------------------------------------------------------------+
|  3 | xp   t !3:124093754-124467278/CNVt 7:78030601-79638023/CNV                                                           |
|  6 | xp                                                                                                                   |
|  9 | xp                                                                                                                   |
| 12 | xp   t !1:84289718-85466763/CNV                                                                                      |
| 15 | xp                                                                                                                   |
| 18 | xp                                                                                                                   |
| 21 | xp                                                                                                                   |
| 24 | xp                                                                                                                   |
| 27 | xp                                                                                                                   |
| 30 | xp   t !10:166909544-166909544/SNPt !2:66903445-66903445/SNPt !2:166897864-166897864/CNVt !7:6892788-6892788/SNP     |
+----+----------------------------------------------------------------------------------------------------------------------+

所以我希望 TEST.Variations 表在转换后是这样的:

+----+-----+-----------+-----------+----------+
| id | chr | start     | stop      | type     |  
+----+-----+-----------+-----------+----------+
|  3 |   3 | 124093754 | 124467278 | CNV      |
|  3 |   7 |  78030601 |  79638023 | CNV      |
| 12 |   1 |  84289718 |  85466763 | CNV      |
| 30 |  10 | 166909544 | 166909544 | SNP      |
| 30 |   2 |  66903445 |  66903445 | SNP      |
| 30 |   2 | 166897864 | 166897864 | CNV      |
| 30 |   7 |   6892788 |   6892788 | SNP      |
+----+-----+-----------+-----------+----------+

【问题讨论】:

  • 这很可能必须使用某种类型的正则表达式来完成。问题:当字符串在当前 blob 中重复时,t 是否总是出现在需要切分到单独列中的字符串之前? ! 是否与迁移有任何关系,还是应该像示例中那样忽略它?
  • 这在纯 MySQL 查询语言中很难做到和测试;解析 variations blob 列的正确工具是 PHP 或 PERL 等字符串处理语言。
  • @amaster507 - 目前 MySQL 没有实现 REGEX_REPLACE - 类似的功能。
  • 我没有说它确实如此......正如 OllieJones 所说,您将需要另一种语言来进行此更新并使用正则表达式

标签: mysql sql database migration


【解决方案1】:

首先两件事:

  1. id 3 的数据不一致。7:... 之前没有!。我希望这只是一个错字

    xp   t !3:124093754-124467278/CNVt 7:78030601-79638023/CNV
                                      ^^
    
  2. 如果你想在你的目标表中有一个auto_increment 列,那么你的架构应该看起来像这样

    CREATE  TABLE variations 
    (
      `var_id` INT NOT NULL AUTO_INCREMENT,
      `id`    INT, -- id from People goes here and it's not UNIQUE
      `chr`   INT,
      `start` INT,
      `stop`  INT ,
      `type`  ENUM('SNP','INDEL','CNV') DEFAULT NULL,
      PRIMARY KEY (`var_id`) 
    );
    

现在您可以通过查询将数据从People 传输到Variations

INSERT INTO variations (id, chr, start, stop, type)
SELECT id, 
       SUBSTRING_INDEX(variation, ':', 1) chr,
       SUBSTRING_INDEX(SUBSTRING_INDEX(variation, '-', 1), ':', -1) start,
       SUBSTRING_INDEX(SUBSTRING_INDEX(variation, '-', -1), '/', 1) stop,
       SUBSTRING_INDEX(variation, '/', -1) type
  FROM
(
  SELECT p.id, SUBSTRING_INDEX(SUBSTRING_INDEX(p.variations, 't !', n.n), 't !', -1) variation
    FROM 
  (
    SELECT id, SUBSTR(variations, 9) variations
      FROM people 
     WHERE variations LIKE 'xp   t !%'
  ) p CROSS JOIN 
  (
     SELECT a.N + b.N * 10 + 1 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 <= 1 + (LENGTH(p.variations) - LENGTH(REPLACE(p.variations, 't !', ''))) / 3
   ORDER BY id
) q
 ORDER BY id, chr, start, stop, type;

注意:此查询将每个 ID 最多拆分 100 个变体。如果您需要更多或更少,您可以通过使用 n 别名编辑内部子查询来调整限制,这会即时生成数字(计数)表。

结果:

| VAR_ID |身份证 |人力资源 |开始 |停止 |类型 | |--------|----|-----|------------|-----------|----- -| | 1 | 3 | 3 | 124093754 | 124467278 | CNV | | 2 | 3 | 7 | 78030601 | 79638023 | CNV | | 3 | 12 | 1 | 84289718 | 85466763 | CNV | | 4 | 30 | 10 | 166909544 | 166909544 |单核苷酸多态性 | | 5 | 30 | 2 | 166897864 | 166897864 | CNV | | 6 | 30 | 2 | 66903445 | 66903445 |单核苷酸多态性 | | 7 | 30 | 7 | 6892788 | 6892788 |单核苷酸多态性 |

这里是SQLFiddle演示

【讨论】:

    猜你喜欢
    • 2014-04-13
    • 2011-09-05
    • 2013-12-13
    • 1970-01-01
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多