在同一MySQL表中复制/复制记录

时间:2009-04-08 11:01:58

标签: 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而不是复制行。有人知道如何解决这个问题吗?

//编辑:我想在不输入所有字段名称的情况下执行此操作,因为字段名称可能会随时间而变化。

10 个答案:

答案 0 :(得分:127)

我通常采用的方式是使用临时表。它可能没有计算效率,但似乎工作正常!在这里,我完整地复制了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;

希望对你有用!

答案 1 :(得分:79)

Alex的回答需要在多客户端环境中进行一些关注(例如锁定或交易)。

假设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 :(得分:11)

你肯定知道,DUPLICATE KEY会触发,因此你可以事先选择MAX(ID)+1:

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

答案 3 :(得分:11)

您的方法很好,但问题是您使用“*”而不是登记字段名称。如果您将所有列名称排除在主键之外,那么您的脚本将在一个或多个记录上像魅力一样工作。

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

答案 4 :(得分:7)

我知道一个迟到的答案,但它仍然是一个常见的问题,我想添加另一个对我有用的答案,只使用单行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;

它非常容易和直接,您可以在一行中更新任何其他内容,而不需要任何第二个更新语句以供日后使用(例如:使用额外文本更新标题列或使用其他文本替换字符串),也可以是具体到你想要复制的内容,如果只是,那么,如果有的话,你可以这样做。

答案 5 :(得分:3)

如果你碰巧要复制一整套记录,我只想扩展亚历克斯的最佳答案:

SET @x=7;
CREATE TEMPORARY TABLE tmp SELECT * FROM invoices;
UPDATE tmp SET id=id+@x;
INSERT INTO invoices SELECT * FROM tmp;

我必须这样做,发现亚历克斯的答案是一个完美的跳跃点!当然,你必须将@x设置为表格中的最高行号(我确定你可以通过查询获取它)。这仅适用于这种非常具体的情况,因此在您不希望复制所有行时请小心使用它。根据需要调整数学。

答案 6 :(得分:2)

我有类似的问题,这就是我正在做的事情

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会自动递增,而且我也会使用固定值(' 23')作为'EncuestaID

答案 7 :(得分:1)

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

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

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

我现在也有这个插件可以重复使用,因为每天都会重写这个表。

答案 8 :(得分:0)

轻微变化,主要区别在于将主键字段(“varname”)设置为null,这会产生警告但有效。通过将主键设置为null,在最后一个语句中插入记录时,自动增量会起作用。

此代码还清除以前的尝试,并且可以多次运行而不会出现问题:

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;

答案 9 :(得分:0)

您可以更改临时表以将ID字段更改为bigint左右,而不需要NOT NULL的要求,然后在该临时表中将ID设置为0。之后,将其添加回原始表,并且NULL将触发自动递增。

CREATE TEMPORARY TABLE tmptable SELECT * FROM x WHERE (id='123');
ALTER TABLE tmptable CHANGE id id bigint;
UPDATE tmptable SET id = NULL;
INSERT INTO x SELECT * FROM tmptable;