我一直在寻找一段时间但我无法找到解决问题的简单方法。我想在表格中复制一条记录,但当然,需要更新唯一的主键。
我有这个问题:
INSERT INTO invoices
SELECT * FROM invoices AS iv WHERE iv.ID=XXXXX
ON DUPLICATE KEY UPDATE ID = (SELECT MAX(ID)+1 FROM invoices)
问题是,这只会更改行的ID
而不是复制行。有人知道如何解决这个问题吗?
//编辑:我想在不输入所有字段名称的情况下执行此操作,因为字段名称可能会随时间而变化。
答案 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;