在MySQL中,我可以复制一行插入到同一个表?

insert into table select * from table where primarykey=1 

我只想复制一行插入到同一个表(即,我想复制表中的现有行),但我想这样做,而不必列出“select”后的所有列,因为这个表太多的专栏。

但是当我这样做,我得到的错误:

键1重复input“xxx”

我可以通过创build另一个具有相同列的表作为我想要复制的logging的临时容器来处理:

 create table oldtable_temp like oldtable; insert into oldtable_temp select * from oldtable where key=1; update oldtable_tem set key=2; insert into oldtable select * from oldtable where key=2; 

有一个更简单的方法来解决这个问题吗?

我用Leonard Challis的技术做了一些改变:

 CREATE TEMPORARY TABLE tmptable_1 SELECT * FROM table WHERE primarykey = 1; UPDATE tmptable_1 SET primarykey = NULL; INSERT INTO table SELECT * FROM tmptable_1; DROP TEMPORARY TABLE IF EXISTS tmptable_1; 

作为临时表,不应该有多于一条logging,所以你不必担心主键。 将它设置为null允许MySQL自己select值,所以没有创build重复的风险。

如果你想超级确定你只得到一行插入,你可以在INSERT INTO行的末尾添加LIMIT 1。

请注意,我还将主键值(本例中为1)附加到我的临时表名称。

更新07/07/2014 – 根据我的回答, Grim …的答案是一个更好的解决scheme,因为它改善了我的解决scheme,所以我build议使用它。

你可以这样做,而不用下面的语法列出所有的列:

 CREATE TEMPORARY TABLE tmptable SELECT * FROM table WHERE primarykey = 1; UPDATE tmptable SET primarykey = 2 WHERE primarykey = 1; INSERT INTO table SELECT * FROM tmptable WHERE primarykey = 2; 

您可以决定以另一种方式更改主键。

我假设你想要新的logging有一个新的主键? 如果主键是AUTO_INCREMENT那么就这样做:

 INSERT INTO table (col1, col2, col3, ...) SELECT col1, col2, col3, ... FROM table WHERE primarykey = 1 

…其中col1, col2, col3, ...除主键以外的表中的所有列。

如果它不是AUTO_INCREMENT列,并且您希望能够为主键select新的值,则它是相似的:

 INSERT INTO table (primarykey, col2, col3, ...) SELECT 567, col2, col3, ... FROM table WHERE primarykey = 1 

…这里567是主键的新值。

您也可以尝试转储表,find插入命令并编辑它:

 mysqldump -umyuser -p mydatabase --skip-extended-insert mytable > outfile.sql 

--skip-extended-insert为每行提供一个插入命令。 然后,您可以在您最喜欢的文本编辑器中find该行,提取命令并将主键更改为“default”。

该过程假定:

  • 你没有_duplicate_temp_table
  • 你的主键是int
  • 你有权限创build表

当然这不是完美的,但在某些(可能是大多数)的情况下,它会起作用。

 DELIMITER $$ CREATE PROCEDURE DUPLICATE_ROW(copytable VARCHAR(255), primarykey VARCHAR(255), copyid INT, out newid INT) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @error=1; SET @temptable = '_duplicate_temp_table'; SET @sql_text = CONCAT('CREATE TABLE ', @temptable, ' LIKE ', copytable); PREPARE stmt FROM @sql_text; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql_text = CONCAT('INSERT INTO ', @temptable, ' SELECT * FROM ', copytable, ' where ', primarykey,'=', copyid); PREPARE stmt FROM @sql_text; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql_text = CONCAT('SELECT max(', primarykey, ')+1 FROM ', copytable, ' INTO @newid'); PREPARE stmt FROM @sql_text; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql_text = CONCAT('UPDATE ', @temptable, ' SET ', primarykey, '=@newid'); PREPARE stmt FROM @sql_text; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql_text = CONCAT('INSERT INTO ', copytable, ' SELECT * FROM ', @temptable, ''); PREPARE stmt FROM @sql_text; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql_text = CONCAT('DROP TABLE ', @temptable); PREPARE stmt FROM @sql_text; EXECUTE stmt; DEALLOCATE PREPARE stmt; SELECT @newid INTO newid; END $$ DELIMITER ; CALL DUPLICATE_ROW('table', 'primarykey', 1, @duplicate_id); SELECT @duplicate_id; 

下面的一些是从这个网站收集的。 这是我做了什么复制表中的任何数量的字段的logging:

这也假设你在表格的开头有一个AI字段

 function duplicateRow( $id = 1 ){ dbLink();//my db connection $qColumnNames = mysql_query("SHOW COLUMNS FROM table") or die("mysql error"); $numColumns = mysql_num_rows($qColumnNames); for ($x = 0;$x < $numColumns;$x++){ $colname[] = mysql_fetch_row($qColumnNames); } $sql = "SELECT * FROM table WHERE tableId = '$id'"; $row = mysql_fetch_row(mysql_query($sql)); $sql = "INSERT INTO table SET "; for($i=1;$i<count($colname)-4;$i++){//i set to 1 to preclude the id field //we set count($colname)-4 to avoid the last 4 fields (good for our implementation) $sql .= "`".$colname[$i][0]."` = '".$row[$i]. "', "; } $sql .= " CreateTime = NOW()";// we need the new record to have a new timestamp mysql_query($sql); $sql = "SELECT MAX(tableId) FROM table"; $res = mysql_query($sql); $row = mysql_fetch_row($res); return $row[0];//gives the new ID from auto incrementing } 

如果您的表的主键字段是一个自动增量字段,那么您可以使用带有列的查询。 例如,名为test_tbl的表有3个字段,分别为id, name, ageid是主键字段和自动增量,因此您可以使用以下查询来复制该行:

 INSERT INTO `test_tbl` (`name`,`age`) SELECT `name`,`age` FROM `test_tbl`; 

此查询导致每一行都重复。


如果您的表的主键字段不是自动增量字段,则可以使用以下方法:

 INSERT INTO `test_tbl` (`id`,`name`,`age`) SELECT 20,`name`,`age` FROM `test_tbl` WHERE id = 19; 

这个查询的结果是插入id=20id=19的重复行。

我可能会迟到,但我有一个类似的解决scheme已经为我工作。

  INSERT INTO `orders` SELECT MAX(`order_id`)+1,`container_id`, `order_date`, `receive_date`, `timestamp` FROM `orders` WHERE `order_id` = 1 

这样我就不需要创build一个临时表格等了。由于行被复制在同一个表中, Max(PK)+1函数可以很容易地使用。

我来找这个问题的解决scheme(已经忘记了语法),我最终做出自己的查询。 有趣的是,事情有时会发生。

问候

我更新了@ LeonardChallis的解决scheme,因为它不适用于我。 我删除了临时表中的WHERE子句和SET primaryKey = 0 ,所以MySQL会自动将主键递增

 CREATE TEMPORARY TABLE tmptable SELECT * FROM myTable; UPDATE tmptable SET primaryKey = 0; INSERT INTO myTable SELECT * FROM tmptable; 

这当然是为了复制表中的所有行。

你几乎已经用你的第一个查询来指定列,这样你可以在插入中排除主键,这将实现你可能在表上自动增加自动创build一个新的主键条目。

例如改变这个:

 insert into table select * from table where primarykey=1 

对此:

 INSERT INTO table (col1, col2, col3) SELECT col1, col2, col3 FROM table WHERE primarykey = 1 

不要将主键列包含在INSERT的列列表中或查询的SELECT部分​​中。

我只需要这样做,这是我的手动解决scheme:

  1. phpmyadmin中 ,检查你想要复制的行
  2. 在查询结果操作的底部,单击“导出”
  3. 在下一页检查“另存为文件”,然后点击“开始”
  4. 用文本编辑器打开导出的文件,find主字段的值,并将其更改为唯一的值。
  5. 回到phpmyadmin点击“导入”标签,find要导入的.sql文件在浏览下的文件,点击“开始” ,应该插入重复的行。

如果你不知道PRIMARY字段是什么,请回头看看你的phpmyadmin页面,点击'Structure'选项卡,在'Indexes'下面的页面底部会显示哪个'Field'有一个'Keyname'“主”

有一段很长的路,但如果你不想处理标记,只需要复制一个单一的行,你去。

如果主键是自动递增,只需指定除主键以外的每个字段。

INSERT INTO table(field1,field2,field3) SELECT (field1,field2,field3) FROM table WHERE primarykey=1

这可以通过一些创造性来实现:

 SET @sql = CONCAT('INSERT INTO <table> SELECT null, ', (SELECT GROUP_CONCAT(COLUMN_NAME) FROM information_schema.columns WHERE table_schema = '<database>' AND table_name = '<table>' AND column_name NOT IN ('id')), ' from <table> WHERE id = <id>'); PREPARE stmt1 FROM @sql; EXECUTE stmt1; 

这将导致新行获得一个自动递增的id,而不是所选行中的id。

我对Grim的技术进行了一些改动:如果有人在寻找这个查询,是因为主键问题而无法做一个简单的查询:

 INSERT INTO table SELECT * FROM table WHERE primakey=1; 

使用我的MySql安装5.6.26,密钥不能为空,并产生一个错误:

 #1048 - Column 'primakey' cannot be null 

所以在创build临时表后,我将主键更改为可空。

 CREATE TEMPORARY TABLE tmptable_1 SELECT * FROM table WHERE primarykey = 1; ALTER TABLE tmptable_1 MODIFY primarykey int(12) null; UPDATE tmptable_1 SET primarykey = NULL; INSERT INTO table SELECT * FROM tmptable_1; DROP TEMPORARY TABLE IF EXISTS tmptable_1; 

我会在下面使用,

 insert into ORDER_ITEM select * from ORDER_ITEM where ITEM_NUMBER =123; 

对不起necropost,但这是我与谷歌发现,因为我发现这有帮助,但有问题,我想为其他人谁挖掘了一个重要的修改。

首先,我正在使用SQL Server,而不是MySQL,但我认为它应该类似地工作。 我使用了Leonard Challis的解决scheme,因为它是最简单的,并且满足了需求,但是有一个问题 – 如果你简单地把PK加1,那么如果你添加了其他logging, 。 我决定最好让系统处理PK的自动增量,所以我做了以下工作:

 SELECT * INTO #tmpTable FROM Table WHERE primarykey = 1 --Optionally you can modify one or more fields here like this: --UPDATE #tmpTable SET somefield = newData ALTER TABLE #tmpTable DROP COLUMN TicketUpdateID INSERT INTO Tickets SELECT * FROM #tmpTable DROP TABLE #tmpTable 

我相信这将在MySQL中类似的工作,但我不能testing这个,对不起

我知道这是一个老问题,但这是另一个解决scheme:

这将在主表中复制一行,假定主键是自动递增的,并使用新的主表ID创build链接表数据的副本。

获取列名的其他选项:
– 来自tablename (专栏名称:Field)
-DESCRIBE tablename (列名:字段)
-SELECT column_name FROM information_schema.columns WHERE table_name ='tablename'(列名:column_name)

 //First, copy main_table row $ColumnHdr=''; $Query="SHOW COLUMNS FROM `main_table`;"; $Result=Wrappedmysql_query($Query,$link,__FILE__,__LINE__); while($Row=mysql_fetch_array($Result)) { if($Row['Field']=='MainTableID') //skip main table id in column list continue; $ColumnHdr.=",`" . $Row['Field'] . "`"; } $Query="INSERT INTO `main_table` (" . substr($ColumnHdr,1) . ") (SELECT " . substr($ColumnHdr,1) . " FROM `main_table` WHERE `MainTableID`=" . $OldMainTableID . ");"; $Result=Wrappedmysql_query($Query,$link,__FILE__,__LINE__); $NewMainTableID=mysql_insert_id($link); //Change the name (assumes a 30 char field) $Query="UPDATE `main_table` SET `Title`=CONCAT(SUBSTRING(`Title`,1,25),' Copy') WHERE `MainTableID`=" . $NewMainTableID . ";"; $Result=Wrappedmysql_query($Query,$link,__FILE__,__LINE__); //now copy in the linked tables $TableArr=array("main_table_link1","main_table_link2","main_table_link3"); foreach($TableArr as $TableArrK=>$TableArrV) { $ColumnHdr=''; $Query="SHOW COLUMNS FROM `" . $TableArrV . "`;"; $Result=Wrappedmysql_query($Query,$link,__FILE__,__LINE__); while($Row=mysql_fetch_array($Result)) { if($Row['Field']=='MainTableID') //skip main table id in column list, re-added in query continue; if($Row['Field']=='dbID') //skip auto-increment,primary key in linked table continue; $ColumnHdr.=",`" . $Row['Field'] . "`"; } $Query="INSERT INTO `" . $TableArrV . "` (`MainTableID`," . substr($ColumnHdr,1) . ") (SELECT " . $NewMainTableID . "," . substr($ColumnHdr,1) . " FROM `" . $TableArrV . "` WHERE `MainTableID`=" . $OldMainTableID . ");"; $Result=Wrappedmysql_query($Query,$link,__FILE__,__LINE__); } 

max233当然是在正确的轨道上,至less在自动增量的情况下。 但是,不要执行ALTER TABLE。 只需将临时表中的自动增量字段设置为NULL即可。 这将会出现错误,但临时表中所有字段的以下INSERT将会发生,并且NULL自动字段将获得唯一值。

创build一个表

  CREATE TABLE `sample_table` ( `sample_id` INT(10) unsigned NOT NULL AUTO_INCREMENT, `sample_name` VARCHAR(255) NOT NULL, `sample_col_1` TINYINT(1) NOT NULL, `sample_col_2` TINYINT(2) NOT NULL, PRIMARY KEY (`sample_id`), UNIQUE KEY `sample_id` (`sample_id`) ) ENGINE='InnoDB' DEFAULT CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'; 

插入一行

 INSERT INTO `sample_table` VALUES(NULL, 'sample name', 1, 2); 

上面的克隆行插入

 INSERT INTO `sample_table` SELECT NULL AS `sample_id`, -- new AUTO_INCREMENT PRIMARY KEY from MySQL 'new dummy entry' AS `sample_name`, -- new UNIQUE KEY from you `sample_col_1`, -- col from old row `sample_col_2` -- col from old row FROM `sample_table` WHERE `sample_id` = 1; 

testing

 SELECT * FROM `sample_table`; 

这里是我在网站上find的答案描述如何做到以上1您可以在页面底部find答案。 基本上,你要做的是复制要复制到内存中的临时表的行。 然后,您使用更新更改主键号码。 然后重新将其插入到目标表中。 然后你放下桌子。

这是它的代码:

CREATE TEMPORARY TABLE rescueteam ENGINE = MEMORY SELECT * FROM fitnessreport4 WHERE rID = 1;#1行受影响。 UPDATE rescueteam SET rID = Null WHERE rID = 1;#1 row affected.INSERT INTO fitnessreport4 SELECT * FROM rescueteam ;#1 row affected。 DROP TABLE rescueteam #MySQL返回一个空的结果集(即零
行)。

我创build了临时表rescueteam。 我从我原来的表fitnessreport4复制行。 然后,将临时表中的行的主键设置为空,以便我可以将其复制回原始表,而不会出现“重复键”错误。 我昨天晚上尝试了这个代码,它工作。

对于一个非常简单的解决scheme,您可以使用PHPMyAdmin将该行导出为CSV文件,然后只需导入修改后的CSV文件。 在导入之前,编辑ID / primarykey列以显示没有值。

 SELECT * FROM table where primarykey=1 

然后在页面的底部:

在这里输入图像描述

在哪里说“导出”只是导出,然后编辑csv文件删除主键值,所以它是空的,然后只是将其导入到数据库中,一个新的主键将被分配导入。

只是想发布我的一段PHP代码,因为我认为收集列的方式比前面的例子更清晰。 此外,这显示了如何轻松地更改字段,在这种情况下,添加一个string。 但是,如果您想复制一些子logging,也可以用新添加的loggingreplace外键字段。

  // Read columns, unset the PK (always the first field in my case) $stmt = $conn->prepare('SHOW COLUMNS FROM template'); $stmt->execute(); $columns = $stmt->fetchAll(); $columns = array_map(function ($element) { return $element['Field']; }, $columns); unset($columns[0]); // Insert record in the database. Add string COPY to the name field. $sql = "INSERT INTO `template` (".implode(",", $columns).")"; if ($key = array_search('name', $columns)) $columns[$key] = "CONCAT(name, ' COPY')"; $sql .= " SELECT ".implode(",", $columns)." FROM `template` WHERE `id` = ".$id; $stmt = $conn->prepare($sql); $stmt->execute(); 

上面显示的这个解决scheme对于选定行也是完美的。 例如,我正在为我的nice2work项目创build演示行,而且这个工作非常完美。

 CREATE TEMPORARY TABLE tmptable SELECT * FROM myTable WHERE id=500; UPDATE tmptable SET id = 0; UPDATE some fields I need to change INSERT INTO myTable SELECT * FROM tmptable; DROP TABLE tmptable; // You can use this same also directly into your code like (PHP Style) $sql = "CREATE TEMPORARY TABLE tmptable SELECT * FROM myTable WHERE id=500; UPDATE tmptable SET id = 0; UPDATE some fields I need to change INSERT INTO myTable SELECT * FROM tmptable;DROP TABLE tmptable;";