MySQL动态INSERT INTO来自另一个表的非规范化表

时间:2015-01-08 03:27:34

标签: mysql

我们说我有表A ,行数为300k

+---------+---------+---------+--------+--------
|   id    | Col1    |  Col2   |  Col 3 | Col n..
+---------+---------+---------+--------+--------
| id val  | Value 1 | Value 2 |  Val 3 | n..
+---------+---------+---------+--------+--------

我想创建一个看似

的非规范化表B
+---------+---------+---------+
|tab_a_id |  Key    |  Val    |  
+---------+---------+---------+
| id val  | Col 1   | Value 1 |  
+---------+---------+---------+
| id val  | Col 2   | Value 2 |  
+---------+---------+---------+
| id val  | Col 3   | Val 3   |  
+---------+---------+---------+
| id val  | Col n.. | n..     |  

有没有办法动态运行表A的列,将其插入到表B中,其中ID为表A,列名为Key,每列的值为?

1 个答案:

答案 0 :(得分:1)

TableA移至TableB

的一种方式
INSERT INTO tableb (tab_a_id, `key`, val)
SELECT a.id, 
       CASE n.n 
          WHEN 1 THEN 'Col1'
          WHEN 2 THEN 'Col2'
          WHEN 3 THEN 'Col3'
          ...
       END,
       CASE n.n 
          WHEN 1 THEN Col1
          WHEN 2 THEN Col2
          WHEN 3 THEN Col3
          ...
       END
  FROM tablea a CROSS JOIN
(
  SELECT 1 n UNION ALL
  SELECT 2 UNION ALL
  SELECT 3 
  ...
) n
 ORDER BY a.id, n.n;

结果:

| TAB_A_ID |  KEY |     VAL |
|----------|------|---------|
|   id val | Col1 | Value 1 |
|   id val | Col2 | Value 2 |
|   id val | Col3 | Value 3 |

这是 SQLFiddle 演示


现在,如果你想让它完全动态,你可以利用动态sql并将其包装到存储过程中以方便

DELIMITER //
CREATE PROCEDURE unpivot()
BEGIN
  SET @sql = NULL, @c = NULL, @v = NULL, @n = NULL;

  SELECT GROUP_CONCAT(CONCAT('WHEN ', ordinal_position, ' THEN ''', column_name, '''') SEPARATOR ' '),
         GROUP_CONCAT(CONCAT('WHEN ', ordinal_position, ' THEN `', column_name, '`') SEPARATOR ' '),
         GROUP_CONCAT(CONCAT('SELECT ', ordinal_position, ' n') SEPARATOR ' UNION ALL ')
    INTO @c, @v, @n
    FROM INFORMATION_SCHEMA.columns
   WHERE table_schema = SCHEMA()
     AND table_name = 'TableA'
     AND column_name NOT IN ('id');

  SET @sql = CONCAT(
    'INSERT INTO tableb (tab_a_id, `key`, val) ',
    'SELECT a.id, CASE n.n ', @c, ' END, CASE n.n ', @v, ' END ',
    'FROM tablea a CROSS JOIN (', @n, ') n ORDER BY a.id, n.n'
  );

  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
END//
DELIMITER ;

使用它:

CALL unpivot();

这是 SQLFiddle 演示