【问题标题】:MySQL: splits row into multiple rows with join table?MySQL:使用连接表将行拆分为多行?
【发布时间】:2012-12-10 16:50:02
【问题描述】:

我有一个具有以下结构的现有表

+-------------+-------+-------+-------+
| employee_id | val_1 | val_2 | val_3 | ...
+-------------+-------+-------+-------+
|         123 |     A |     B |     C |

我想将这个表更改为 2 个表 - 一个包含单独行中的值,另一个包含为此的连接表。例如,上面会变成这样:

+-------------+--------+      +----+-------+
| employee_id | val_id |      | id | value |
+-------------+--------+      +----+-------+
|         123 |      1 |      |  1 |     A |
+-------------+--------+      +----+-------+
|         123 |      2 |      |  2 |     B |
+-------------+--------+      +----+-------+
|         123 |      3 |      |  3 |     C |
+-------------+--------+      +----+-------+

将现有表转换为这两个新表的最佳 SQL 是什么?我可以很容易地创建值表,但我不确定如何同时创建连接表。

【问题讨论】:

  • 抱歉不精通 MySQL,但任何答案都应该考虑到您的原始表可能对employee_id 有唯一性约束(例如,如果它是主键),这将导致您的新表格式出现问题...需要删除、放宽/扩展约束(例如,employee_id 和 val_id 上的复合 PK),或者创建一个 new 员工表可能更容易(当然建议复制而不是替换,无论如何,用于测试接受的任何答案)。
  • 您希望从选择中为原始表的每一列运行插入。我会发布一个完整的答案,但现在不能打扰测试准确性。
  • 嗨 Sepster - 这两个表都是新的,所以他们不必担心现有表的约束?
  • 嗨 mikebabcock,这就是我正在做的创建新值表的工作,我只是不确定如何在执行此操作时填充连接表...
  • @JohnFarrelly 是的,你是对的,对不起 - 我误解了你正在创建新表。 PS 在用户名前使用@,以确保他们收到您在评论中提到他们的通知

标签: mysql sql


【解决方案1】:

类似这样的东西(仅限伪代码,抱歉):

For each row in (SELECT employee_id, val_1, val_2, val_3 FROM existing_table)
{
   for each val in (row.Values)
   {
     INSERT INTO new_values (val)
     val_id = SELECT LAST_INSERT_ID();
     INSERT INTO new_employees (employee_id, val_id);
  }
}

可能有一种基于集合的方法来避免循环......但抱歉,我不知道它和你一样,我不确定如何取回值表的标识到父员工表中。

而且,虽然cursors 通常不被接受,但这种一次性操作正是它们的设计目的(即,我不建议将游标用于常规事务或报告处理,而是用于重新数据结构......为什么不呢?)。

【讨论】:

  • 是的,这就是我想做的,我只是不确定 MySQL 语法:) 例如,我想知道是否必须创建一个过程来放入循环,或者MySQL 可以处理即席循环语句吗?
【解决方案2】:

第一个结果

`INSERT INTO new_val
SELECT  emp_id, REPLACE(UPPER(column_name), 'VAL_', '') FROM   
information_schema.COLUMNS ,
employee
WHERE TABLE_NAME = 'employee' AND TABLE_SCHEMA = 'myschema' AND column_name LIKE 'VAL_%'`;


使用第一个结果,填充查询并使用它插入新表; 可能需要进行微调。未测试
SELECT CONCAT('select ', new_val.number, ', VAL_', new_val.number, ' FROM employee, new_val WHERE new_val.emp_id = employee.emp_id and new_val.number = ', val.number, ' union all' ) FROM val ;

【讨论】:

  • 我是 stackoverflow 的新手,格式不好。请原谅
【解决方案3】:

所以这就是我最终写的内容。正如程序名称所暗示的那样,我期待有一种更直接的方法来做到这一点!

CREATE PROCEDURE iWasHopingItWouldBeSimpler()
BEGIN
   DECLARE loop_done BOOLEAN DEFAULT 0;

   DECLARE emp_id BIGINT(20);
   DECLARE val1 DECIMAL(19,2);
   DECLARE val2 DECIMAL(19,2);
   DECLARE val3 DECIMAL(19,2);

   DECLARE emp CURSOR
   FOR
   SELECT employee_id, val1, val2, val3 FROM existing;   

   -- Declare continue handler
   DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET loop_done=1;

   OPEN emp;

   -- Loop through all rows
   REPEAT
      FETCH emp INTO emp_id, val1, val2, val3;

      INSERT INTO new_values (value) VALUES(val1);
      INSERT INTO new_join (employee_id, values_id) VALUES(emp_id, LAST_INSERT_ID());

      INSERT INTO new_values (value) VALUES(val2);
      INSERT INTO new_join (employee_id, values_id) VALUES(emp_id, LAST_INSERT_ID());

      INSERT INTO new_values (value) VALUES(val3);
      INSERT INTO new_join (employee_id, values_id) VALUES(emp_id, LAST_INSERT_ID());

   -- End of loop
   UNTIL loop_done END REPEAT;

   CLOSE emp;
   SET loop_done=0;
END;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 1970-01-01
    • 2015-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-14
    相关资源
    最近更新 更多