我们说我有表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,每列的值为?
答案 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 演示