2009-04-08 147 views
75

我一直在寻找一段时间,但我找不到解决我的问题的简单方法。我想在表中复制一条记录,但当然,唯一的主键需要更新。在同一个MySQL表中复制/复制记录

我有这个疑问:

INSERT INTO invoices 
    SELECT * FROM invoices AS iv WHERE iv.ID=XXXXX 
    ON DUPLICATE KEY UPDATE ID = (SELECT MAX(ID)+1 FROM invoices) 

的问题是,这只是改变了该行的ID而不是复制的行。有人知道如何解决这个问题吗?

//编辑:我想这样做而不输入所有的字段名称,因为字段名称可以随时间变化。

回答

115

我通常使用的方式是使用临时表。这可能不是计算效率高,但它似乎工作正常!我在这里重复记录99的全部,创记录的100

CREATE TEMPORARY TABLE tmp SELECT * FROM invoices WHERE id = 99; 

UPDATE tmp SET id=100 WHERE id = 99; 

INSERT INTO invoices SELECT * FROM tmp WHERE id = 100; 

希望对你有用ok了!

+0

我喜欢它,中间要留意一些东西 – SeanDowney 2011-05-04 21:54:26

+3

如果您要复制单个记录,则可以删除更新和插入的位置。然后你可以在mysql控制台中按两次,这会弹出历史记录中的倒数第二个操作,在最后更改方便的update中的id,按回车键,按下,再次敲入,而不改变任何内容,然后重复该程序为多个副本。快多了。 – 2012-03-12 22:57:20

11

你肯定知道,那重复键将触发,所以你可以选择MAX(ID)+1事先:

INSERT INTO invoices SELECT MAX(ID)+1, ... other fields ... FROM invoices AS iv WHERE iv.ID=XXXXX 
+1

是的,但我不想输入所有其他字段(大约有20个字段,它们可能会随时间而改变)。每当表结构发生变化时,我都不想更改代码。 – Digits 2009-04-08 11:17:40

+0

你必须。您最好制作一个从字段列表中生成SQL语句的脚本。这是微不足道的。 – Ingo 2009-04-08 11:27:07

+0

唯一的另一种选择是使用插入触发器(如果mysql支持的话)。 – Ingo 2009-04-08 11:29:09

1

我需要这个为好;我的解决方案是使用SQLYOG(免费版)将所需记录导出为SQL(创建插入)。

然后,我手编辑这个删除id,因为这需要自动生成,然后将插入复制到SQLYog执行它。这是无痛的。我猜大量的其他MySQL GUI也可以做到这一点。

这为我提供了一个记录,我可以将它用于实时系统的测试目的。

我现在也有这个插入以供重用,因为每天都会重写表。

75

亚历克斯的回答在多客户端环境中需要谨慎(例如锁定或事务)。

假设AUTO ID字段是表中的第一个字段(通常情况下),我们可以使用隐式的 事务。

 
    CREATE TEMPORARY TABLE tmp SELECT * from invoices WHERE ...; 
    ALTER TABLE tmp drop ID; # drop autoincrement field 
    # UPDATE tmp SET ...; # just needed to change other unique keys 
    INSERT INTO invoices SELECT 0,tmp.* FROM tmp; 
    DROP TABLE tmp; 

从MySQL的文档:

使用AUTO_INCREMENT:您也可以明确地指定NULL或0到列生成的序列号。

2

我有一个类似的问题,这是whant我做

insert into Preguntas (`EncuestaID`, `Tipo` , `Seccion` , `RespuestaID` , `Texto`) select '23', `Tipo`, `Seccion`, `RespuestaID`, `Texto` from Preguntas where `EncuestaID`= 18 

去过Preguntas:

CREATE TABLE IF NOT EXISTS `Preguntas` (
    `ID` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `EncuestaID` int(11) DEFAULT NULL, 
    `Tipo` char(5) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `Seccion` int(11) DEFAULT NULL, 
    `RespuestaID` bigint(11) DEFAULT NULL, 
    `Texto` text COLLATE utf8_unicode_ci , 
    PRIMARY KEY (`ID`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=522 ; 

因此,ID自动递增,也是我正在使用EncuestaID的固定值('23')

10

您的方法很好,但问题在于您使用“*”代替了注册字段名称秒。如果你把所有的列名称作为主键,你的脚本将像一个或多个记录上的魅力一样工作。

INSERT INTO invoices (iv.field_name, iv.field_name,iv.field_name ) SELECT iv.field_name, iv.field_name,iv.field_name FROM invoices AS iv WHERE iv.ID=XXXXX

0

轻微变化,主要的区别是,设置主键字段(“varname的”)为空,其产生警告,但工作原理。通过将主键设置为空,当在最后一条语句中插入记录时,自动递增工作。

此代码还清理以前的尝试,并且可以毫无问题地运行了不止一次:

DELETE FROM `tbl` WHERE varname="primary key value for new record"; 
DROP TABLE tmp; 
CREATE TEMPORARY TABLE tmp SELECT * FROM `tbl` WHERE varname="primary key value for old record"; 
UPDATE tmp SET varname=NULL; 
INSERT INTO `tbl` SELECT * FROM tmp; 
1

我只是想延长Alex的伟大答案,使之适宜,如果你碰巧要复制整个一套记录:

SET @x=7; 
CREATE TEMPORARY TABLE tmp SELECT * FROM invoices; 
UPDATE tmp SET [email protected]; 
INSERT INTO invoices SELECT * FROM tmp; 

我只是要做到这一点,发现亚历克斯的答案是一个完美的跳跃点!当然,你必须将@x设置为表格中最高的行数(我相信你可以通过查询来获取)。这只适用于这种非常特殊的情况,所以当你不想复制所有行时要小心使用它。根据需要调整数学。

3

我知道一个迟到的答案,但它仍然是一个常见问题,我想添加另一个答案,它为我工作,只使用单行insert into声明,我认为它是直接的,没有创建任何新表(因为它可能是与CREATE TEMPORARY TABLE权限的问题):

INSERT INTO invoices (col_1, col_2, col_3, ... etc) 
    SELECT 
    t.col_1, 
    t.col_2, 
    t.col_3, 
    ... 
    t.updated_date, 
    FROM invoices t; 

的解决方案正在为AUTO_INCREMENT id列,否则,您可以添加ID列,以及对声明:

INSERT INTO invoices (ID, col_1, col_2, col_3, ... etc) 
    SELECT 
    MAX(ID)+1, 
    t.col_1, 
    t.col_2, 
    t.col_3, 
    ... etc , 
    FROM invoices t; 

它非常简单直接,您可以在一行中更新其他任何内容,而不需要第二次更新语句以备后用(例如:用额外文本更新标题列或用另一个字符串替换字符串),也可以指定你想要复制什么,如果全部是这样的话,如果有的话,你可以这样做。