如何在MySQL中使用自动递增字段复制一行并将其插入到同一表中?


233

在MySQL中,我试图复制一排的自动增量 column ID=1插入数据到同一个表的新行column ID=2

如何在单个查询中执行此操作?

Answers:


351

用途INSERT ... SELECT

insert into your_table (c1, c2, ...)
select c1, c2, ...
from your_table
where id = 1

c1, c2, ...除以外的所有列都在哪里id?如果要显式插入id2,则将其包括在INSERT列列表和SELECT中:

insert into your_table (id, c1, c2, ...)
select 2, c1, c2, ...
from your_table
where id = 1

id当然,在第二种情况下,您必须注意2 的可能重复项。


1
您可以使用INFORMATION_SCHEMA以编程方式获取列的名称...我想知道是否可以将其作为子查询和某些字符串函数来使用?嗯...
伊兹密尔·拉米雷斯

1
@Yzmir:您最终不得不使用动态SQL,这通常需要构建存储过程。无论如何,当您应该方便地使用列名称列表时,似乎麻烦多于其应有的价值。
亩太短

6
同意...根据我的经验,一旦您执行存储过程,就不会再回头了-您现在已与该数据库结婚,并且只要需要更改便会增加成本。
伊兹密尔·拉米雷斯

11
@YzmirRamirez,听起来像婚姻本质上是一件坏事。:)
Falken教授

1
如何在具有所有其他复制字段的列中添加一个自定义值?
Manish Kumar

49

IMO,最好似乎只使用sql语句来复制该行,而同时仅引用必须且要更改的列。

CREATE TEMPORARY TABLE temp_table ENGINE=MEMORY

SELECT * FROM your_table WHERE id=1;
UPDATE temp_table SET id=NULL; /* Update other values at will. */

INSERT INTO your_table SELECT * FROM temp_table;
DROP TABLE temp_table;

另请参见av8n.com-如何克隆SQL记录

好处:

  • SQL语句2仅提及在克隆过程中需要更改的字段。他们不了解或关心其他领域。其他字段只是顺风顺水,没有变化。这使SQL语句更易于编写,易于阅读,易于维护和可扩展。
  • 仅使用普通的MySQL语句。不需要其他工具或编程语言。
  • your_table在一个原子操作中插入了完全正确的记录。

3
它似乎表明,这个不错的技巧(我喜欢它,但对我而言不起作用)不适用于包含TEXT / VARCHAR列的表。我尝试过并得到:(1163):使用的表类型不支持BLOB / TEXT列。当然,这极大地限制了MySQL的使用!可能是,将来会取消这些限制,或者在其他数据库系统上确实会解决这些限制,但现在确实是有限的。

我真的很喜欢临时表的巧妙使用。对于具有大量列的表非常有用!
Lasma

1
看起来不错,但是当我在MySQL中运行第一个查询时,我得到了Error Code: 1113. A table must have at least 1 column
物理

3
很多专栏文章的最佳答案。但是SET id=NULL可能会导致错误Column 'id' cannot be null。应该替换为UPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
Modder

1
@physicalattraction您需要确保前两行是一个语句。
Samuurai

16

说桌子是user(id, user_name, user_email)

您可以使用以下查询:

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)

29
使用INSERT时,应始终指定列名,否则在更改架构时会遇到奇怪而有趣的错误。
亩太短

2
确实很奇怪和有趣。:D
sparkyShorts 2015年

不适用于sqlite。 Result: near "SELECT": syntax error
kyb

10

这有所帮助,它支持BLOB / TEXT列。

CREATE TEMPORARY TABLE temp_table
AS
SELECT * FROM source_table WHERE id=2;
UPDATE temp_table SET id=NULL WHERE id=2;
INSERT INTO source_table SELECT * FROM temp_table;
DROP TEMPORARY TABLE temp_table;
USE source_table;

以什么方式比这里的其他答案更好?
Smar 2016年

3
我认为如果您有一个包含100个字段的表,那会很好。除了可能存在的ID NOT NULL约束,这使得它失败
卢瓦克福雷-拉克鲁瓦

错误代码:1136。列计数与第1行的值计数不匹配
Oleksii Kyslytsyn

如果您有一个包含100列的表,则效果会更好。
泰勒·洛珀

这不是几年前帕维斯所说的吗?
ToolmakerSteve

7

对于不需要您命名列的快速,干净的解决方案,可以使用如下所述的准备好的语句:https : //stackoverflow.com/a/23964285/292677

如果您需要一个复杂的解决方案以便可以经常执行此操作,则可以使用以下过程:

DELIMITER $$

CREATE PROCEDURE `duplicateRows`(_schemaName text, _tableName text, _whereClause text, _omitColumns text)
SQL SECURITY INVOKER
BEGIN
  SELECT IF(TRIM(_omitColumns) <> '', CONCAT('id', ',', TRIM(_omitColumns)), 'id') INTO @omitColumns;

  SELECT GROUP_CONCAT(COLUMN_NAME) FROM information_schema.columns 
  WHERE table_schema = _schemaName AND table_name = _tableName AND FIND_IN_SET(COLUMN_NAME,@omitColumns) = 0 ORDER BY ORDINAL_POSITION INTO @columns;

  SET @sql = CONCAT('INSERT INTO ', _tableName, '(', @columns, ')',
  'SELECT ', @columns, 
  ' FROM ', _schemaName, '.', _tableName, ' ',  _whereClause);

  PREPARE stmt1 FROM @sql;
  EXECUTE stmt1;
END

您可以使用以下命令运行它:

CALL duplicateRows('database', 'table', 'WHERE condition = optional', 'omit_columns_optional');

例子

duplicateRows('acl', 'users', 'WHERE id = 200'); -- will duplicate the row for the user with id 200
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts'); -- same as above but will not copy the created_ts column value    
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts,updated_ts'); -- same as above but also omits the updated_ts column
duplicateRows('acl', 'users'); -- will duplicate all records in the table

免责声明:此解决方案仅适用于经常在许多表中重复复制行的人。在流氓用户的手中这可能很危险。


3

您还可以输入“ 0”作为要自动增加的列的值,创建记录时将使用正确的值。这比临时表容易得多。

来源: 在MySQL中复制行 (请参阅TRiG的第二条评论到Lore的第一个解决方案)


1
如果不接受NULL,则此方法适用于更新的MySQL版本。
err

3

这里有很多很好的答案。以下是为完成我正在开发的Web App的任务而编写的存储过程的示例:

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON

-- Create Temporary Table
SELECT * INTO #tempTable FROM <YourTable> WHERE Id = Id

--To trigger the auto increment
UPDATE #tempTable SET Id = NULL 

--Update new data row in #tempTable here!

--Insert duplicate row with modified data back into your table
INSERT INTO <YourTable> SELECT * FROM #tempTable

-- Drop Temporary Table
DROP TABLE #tempTable

在当前版本的MariaDB / MySQL中,设置id = null给出#1048-列'id'不能为null,设置id = 0起作用;
shelbypereira

2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;

3
这比这里的其他答案好吗?
2016年

1
@smar imo易于理解
Satbir Kira

2

如果能够使用MySQL Workbench,可以通过右键单击该行并选择“复制行”,然后右键单击该空行并选择“粘贴行”,然后更改ID,然后再执行此操作点击“应用”。

复制行:

在此处输入图片说明

将复制的行粘贴到空白行:

在此处输入图片说明

更改ID:

在此处输入图片说明

应用:

在此处输入图片说明


0

我一直在寻找相同的功能,但我不使用MySQL。我想复制所有字段,除了主键(id)。这是一次查询,不能在任何脚本或代码中使用。

我找到了使用PL / SQL的方法,但是我确定任何其他SQL IDE都可以。我做了一个基本的

SELECT * 
FROM mytable 
WHERE id=42;

然后将其导出到一个SQL文件中,我可以在其中找到

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (1, 2, 3, ..., 42);

我只是编辑并使用它:

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (mysequence.nextval, 2, 3, ..., 42);

0

我倾向于使用mu太短发布的变体:

INSERT INTO something_log
SELECT NULL, s.*
FROM something AS s
WHERE s.id = 1;

只要这些表具有相同的字段(日志表上的自动增量除外),就可以很好地工作。

由于我尽可能使用存储过程(以简化对数据库不太熟悉的其他程序员的生活),因此解决了每次向表中添加新字段时都必须返回并更新过程的问题。

它还可以确保,如果您将新字段添加到表中,它们将立即开始出现在日志表中,而无需更新数据库查询(当然,除非您有一些字段明确地设置了该字段)

警告:您将要确保同时将所有新字段添加到两个表中,以使字段顺序保持不变...否则,您将开始遇到奇怪的错误。如果您是唯一编写数据库接口的人,并且非常小心,则效果很好。否则,请坚持命名所有字段。

注意:再三考虑一下,除非您正在开发一个单独的项目,否则您确定不会有其他项目在进行,而是坚持明确列出所有字段名称,并在架构更改时更新日志语句。这种捷径可能不值得它引起的长期头痛……尤其是在生产系统上。


0
插入dbMyDataBase.tblMyTable 
(
    `IdAutoincrement`, 
    `Column2`, 
    `Column3`, 
    `Column4` 
) 

选择 
    空值,  
    `Column2`, 
    `Column3`, 
    “ CustomValue” AS Column4 
从`dbMyDataBase`.`tblMyTable` 
tblMyTable`.Column2 ='UniqueValueOfTheKey' 
; 
/ * mySQL 5.6 * /

3
尝试添加一些更详细的解释,或如何扩展其他答案
Azsgy

-1

转储您要使用sql的行,然后使用生成的SQL(减去ID列)将其重新导入。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.