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

Posted

技术标签:

【中文标题】如何在 MySQL 中使用自动增量字段复制行并插入到同一个表中?【英文标题】:How to copy a row and insert in same table with a autoincrement field in MySQL? 【发布时间】:2012-02-27 16:55:42 【问题描述】:

mysql 中,我尝试使用 autoincrement column ID=1 复制一行并将数据insert 复制到同一个表中,作为带有 column ID=2 的新行。

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

【问题讨论】:

【参考方案1】:

使用INSERT ... SELECT:

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

其中c1, c2, ... 是除id 之外的所有列。如果您想使用 2 的 id 显式插入,则将其包含在您的 INSERT 列列表和您的 SELECT 中:

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

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

【讨论】:

您可以使用 INFORMATION_SCHEMA 以编程方式获取列的名称...我想知道您是否可以将其作为子查询和一些字符串函数来执行?嗯... @Yzmir:您最终不得不使用动态 SQL,而这通常需要构建存储过程。无论如何,当你应该有一个方便的列名列表时,这似乎比它的价值更麻烦。 同意...根据我的经验,一旦您使用存储过程,您就不会返回 - 您现在已与该数据库结婚,并且只要您想更改就会增加成本。 @YzmirRamirez,你听起来好像婚姻本质上是一件坏事。 :) 如何在所有其他复制字段的列中添加一个自定义值?【参考方案2】:

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

CREATE TEMPORARY TABLE temp_table ENGINE=MEMORY

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

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

另见av8n.com - How to Clone an SQL Record

好处:

SQL 语句 2 仅提及在克隆过程中需要更改的字段。他们不知道——也不关心——其他领域。其他领域只是顺其自然,不变。这使得 SQL 语句更易于编写、更易于阅读、更易于维护且更具可扩展性。 只使用普通的 MySQL 语句。不需要其他工具或编程语言。 在一次原子操作中将完全正确的记录插入到your_table

【讨论】:

它接缝,这个好技巧(我喜欢它,但它对我不起作用)不适用于包含 TEXT/VARCHAR 列的表。我试了一下,得到:(1163):使用的表类型不支持 BLOB/TEXT 列。这当然极大地限制了 MySQL 上的使用!可能是,将来这些限制会被取消,或者在其他数据库系统上它确实有效,但现在它真的是有限的。 看起来不错,但是当我在 MySQL 中运行第一个查询时,我得到了Error Code: 1113. A table must have at least 1 column 很多专栏的最佳答案。但是SET id=NULL 可能会导致错误Column 'id' cannot be null。应替换为UPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table); @physicalattraction 您需要确保前两行是一个语句。 @Modder - 或SET id = 0 - 来自Trig's comment on this answer。【参考方案3】:

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

你可以使用这个查询:

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

【讨论】:

在使用 INSERT 时应该始终指定列名,否则当架构更改时会出现奇怪而有趣的错误。 确实很奇怪,也很有趣。 :D 不适用于 sqlite。 Result: near "SELECT": syntax error【参考方案4】:

这很有帮助,它支持 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;

【讨论】:

在什么方面这比这里的其他答案更好? 我认为如果您有一个包含 100 个字段的表,那就太好了。除非 id 上可能有一个非空约束导致它失败 错误代码:1136。列数与第 1 行的值数不匹配 如果您有一个包含 100 列的表,这会更好。 @ToolmakerSteve,另一个显然不支持“BLOB/TEXT 列”。【参考方案5】:

对于不需要您命名列的快速、干净的解决方案,您可以使用如下所述的准备好的语句: https://***.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

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

【讨论】:

【参考方案6】:
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;

【讨论】:

这比这里的其他答案好多少? @smar imo 更容易理解 它保证值被插入到各自的列中。【参考方案7】:

这里有很多很棒的答案。下面是我为正在开发的 Web 应用程序完成此任务而编写的存储过程示例:

-- 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' 不能为空,设置 id=0 有效;【参考方案8】:

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

复制行:

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

更改 ID:

申请:

【讨论】:

【参考方案9】:

您也可以传入'0'作为列的值以自动递增,创建记录时将使用正确的值。这比临时表要容易得多。

来源: Copying rows in MySQL (参见 TRiG 对 Lore 的第一个解决方案的第二条评论)

【讨论】:

当 NULL 不可接受时,此方法适用于较新的 MySQL 版本。【参考方案10】:

我倾向于使用 mu is too short 张贴的变体:

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

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

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

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

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

注意:再想一想,除非您正在处理一个单独的项目,否则您确定不会让其他人在此工作坚持明确列出所有字段名称并将您的日志语句更新为您的架构更改。这条捷径可能不值得它引起的长期头痛……尤其是在生产系统上。

【讨论】:

【参考方案11】: 插入到`dbMyDataBase`.`tblMyTable` ( `IdAutoincrement`, `列2`, `列 3`, `列4` ) 选择 空值, `列2`, `列 3`, 'CustomValue' 作为 Column4 FROM `dbMyDataBase`.`tblMyTable` WHERE `tblMyTable`.`Column2` = 'UniqueValueOfTheKey' ; /* mySQL 5.6 */

【讨论】:

尝试添加一些更详细的解释,或者如何扩展其他答案 这其实是正确的答案。是的,它很简洁,但是任何了解 SQL 的人都应该“理解”它。我什至在我的陈述中使用了 REPLACE。【参考方案12】:

试试这个:

INSERT INTO test_table (SELECT null,txt FROM test_table)

每次您运行此查询时,都会使用新的 ID 再次插入所有行。表中的值并将成倍增加。

我使用了一个包含两列的表格,即 id 和 txt,id 是自动递增的。

【讨论】:

【参考方案13】:

我一直在寻找相同的功能,但我不使用 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);

【讨论】:

【参考方案14】:

insert into your_table(col1,col2,col3) select col1+1,col2,col3 from your_table where col1=1;

注意:如果 col1 是主键,请确保增加后 col1 的新值不是重复条目。

【讨论】:

【参考方案15】:
CREATE TEMPORARY  TABLE IF NOT EXISTS  `temp_table` LIKE source_table;
DELETE FROM `purchasing2` ;
INSERT INTO temp_table SELECT * FROM source_table where columnid = 2;
ALTER TABLE temp_table MODIFY id INT NOT NULL;
ALTER TABLE temp_table DROP PRIMARY KEY;
UPDATE temp_table SET id=NULL ;
INSERT INTO source_table SELECT * FROM temp_table;
DROP TEMPORARY  TABLE IF EXISTS  temp_table ; 

【讨论】:

【参考方案16】:

转储你想要 sql 的行,然后使用生成的 SQL,减去 ID 列重新导入。

【讨论】:

您应该更好地详细说明您的答案。 虽然简短,但这是我使用的技术。我相信 OP 在这个答案(SSMS gui 命令)中指的是 Script->Table as Insert 和 Script->Table as Select 。一旦你从生成的 SQL 中删除 PK/IDENTITY 列,这就构成了一个体面的克隆查询的基础。

以上是关于如何在 MySQL 中使用自动增量字段复制行并插入到同一个表中?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 多行插入是不是获取顺序自动增量 ID?

SQL Server:从一个表中复制新添加的行并自动插入到另一个表中

什么可能导致自动增量主键字段(mysql)上的重复 ID?

MYSQL 自动增量按字段分类

mySQL 数据库:重置自动增量字段

JDBC如何在自增字段中插入记录