MySQL INSERT ... 从 1 个表中选择 2 个表

Posted

技术标签:

【中文标题】MySQL INSERT ... 从 1 个表中选择 2 个表【英文标题】:MySQL INSERT ... SELECT from 1 table into 2 tables 【发布时间】:2014-03-04 21:04:55 【问题描述】:

我看到很多关于从多个表中插入单个表的问题。我试图做相反的事情,只使用 MySQL

我有一个包含非规范化数据的临时表。我需要

    遍历临时表的每一行 在主表上使用临时表中的一些字段创建一个新行 使用刚刚创建的主表行的自动增量 ID 在辅助表上创建一个新行,将 LAST_INSERT_ID() 放入 primary_id 字段。

我了解整个 LAST_INSERT_ID() 并且我很高兴运行事务:我只是不知道如何创建循环通过临时表然后运行 ​​2 个后续插入的“外部选择循环”。

【问题讨论】:

您是想从 mysql 本身内部执行此操作,还是使用其他语言的客户端 API? @eggyal mySQL - 查看我更新的评论。感谢您提出问题! 【参考方案1】:

如果临时表中的值是唯一的,这可以工作。这个想法是将插入分成两步,一个进入主表,其余进入辅助表:

insert into primary( . . .)
    select . . .
    from temp;

insert into secondary(primaryid, . . . )
    select p.PrimaryId, t.col . . .
    from temp t join
         primary p
         on t.col1 = p.col1 and . . .;

有一些注意事项。例如,您将需要更复杂的逻辑来处理连接。并且,它假定临时表中的每组主列都是唯一的。

最常见的方法是在使用LAST_INSERT_ID 的存储过程或应用程序代码中循环。

【讨论】:

感谢 Gordon - 这为我指明了正确的方向。你有存储过程方法中循环的例子吗?【参考方案2】:

作为@GordonLinoff said,可以循环访问LAST_INSERT_ID()。如果临时表中的每组主列可能是唯一的,那么基本上有两种方法可以实现这一点:

    依赖于主表中相关列的唯一性约束,以及 MySQL 的 ON DUPLICATE KEY UPDATE 扩展至 INSERT

    CREATE PROCEDURE foo() BEGIN
      DECLARE done BOOLEAN DEFAULT FALSE;
      DECLARE cur CURSOR FOR SELECT . . . FROM temp;
      DECLARE CONTINUE HANDLER FOR NOT FOUND SET done := TRUE;
    
      PREPARE ins1 FROM '
        INSERT INTO primary
          (. . .)
        VALUES
          (?, . . .)
        ON DUPLICATE KEY UPDATE
          PrimaryId = LAST_INSERT_ID(PrimaryId)
      ';
      PREPARE ins2 FROM '
        INSERT INTO secondary
          (primaryid, . . .)
        VALUES
          (LAST_INSERT_ID(), ?, . . .)
      ';
    
      OPEN cur;
      read_loop: LOOP
        FETCH cur INTO @a, @b, . . .;
        IF done THEN
          LEAVE read_loop;
        END IF;
    
        EXECUTE ins1 USING @a, . . .;
        EXECUTE ins2 USING @b, . . .;
      END LOOP;
      CLOSE cur;
    
      DROP PREPARE ins1;
      DROP PREPARE ins2;
    END
    

    按(非唯一)主列按临时表排序,然后跟踪最后看到的值,仅在遇到新记录时插入主表:

    CREATE PROCEDURE foo() BEGIN
      DECLARE done BOOLEAN DEFAULT FALSE;
      DECLARE cur CURSOR FOR SELECT . . . FROM temp ORDER BY . . .;
      DECLARE CONTINUE HANDLER FOR NOT FOUND SET done := TRUE;
    
      PREPARE ins1 FROM '
        INSERT INTO primary
          (. . .)
        VALUES
          (. . .)  -- use "?" placeholders
      ';
      PREPARE ins2 FROM '
        INSERT INTO secondary
          (primaryid, . . .)
        VALUES
          (. . .)  -- use "?" placeholders
      ';
    
      OPEN cur;
      FETCH cur INTO @a, @b, . . .;
      WHILE NOT done DO
        SET @current_a := @a, . . .;  -- (non-unique) primary cols
        EXECUTE ins1 USING @a, . . .;
        SET @primaryid := LAST_INSERT_ID();
    
        REPEAT
          EXECUTE ins2 USING @primaryid, @b, . . .;
          FETCH cur INTO @a, @b, . . .;
        UNTIL done OR @a <> @current_a OR . . . END REPEAT;
      END WHILE;
      CLOSE cur;
    
      DROP PREPARE ins1;
      DROP PREPARE ins2;
    END
    

【讨论】:

以上是关于MySQL INSERT ... 从 1 个表中选择 2 个表的主要内容,如果未能解决你的问题,请参考以下文章

mysql mycat 1.6.6.1-release 批量 insert 数据丢失问题(续)

mysql插入tbl(从2个表中选择)

PHP MYSQL UPDATE 如果存在或 INSERT 如果不存在?

在日期选择器中选择日期之前触发功能

php mysql如何从2个表中选择我需要的[关闭]

从 6 个表构建一个 mysql 查询以减少 php 的使用