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

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

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

【问题讨论】:

    标签: mysql sql insert copy


    【解决方案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://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
    

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

    【讨论】:

      【解决方案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 列,这就构成了一个体面的克隆查询的基础。
                  猜你喜欢
                  • 1970-01-01
                  • 2015-03-11
                  • 2023-03-30
                  • 1970-01-01
                  • 2015-10-14
                  • 2015-04-13
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-10-04
                  相关资源
                  最近更新 更多