首页 文章

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

提问于
浏览
130
insert into table select * from table where primarykey=1

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

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

键1的重复条目'xxx'

我可以通过创建另一个具有相同列的表作为我要复制的记录的临时容器来处理这个问题:

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;

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

24 回答

  • 0

    我使用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;
    

    作为临时表,永远不应该有多个记录,因此您不必担心主键 . 将其设置为null允许MySQL自己选择值,因此不存在创建重复的风险 .

    如果你想要确定你只需要插入一行,你可以将LIMIT 1添加到INSERT INTO行的末尾 .

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

  • 0

    Update 07/07/2014 - The answer based on my answer, by Grim..., is a better solution as it improves on my solution below, so I'd suggest using that.

    您可以使用以下语法在不列出所有列的情况下执行此操作:

    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;
    

    您可以决定以其他方式更改主键 .

  • 2

    我假设您希望新记录有一个新的 primarykey ?如果 primarykeyAUTO_INCREMENT 那么就这样做:

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

    ...其中 col1, col2, col3, ... 是表中除 primarykey 之外的所有列 .

    如果它不是 AUTO_INCREMENT 列,并且您希望能够为 primarykey 选择新值,则类似:

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

    ...其中 567primarykey 的新值 .

  • 35

    您几乎已经使用了第一个查询,只需要指定列,这样您就可以在插入中排除主键,这将生成您可能在表上自动增加的自动增量,以便为表创建新的主键 . 条目 .

    例如改变这个:

    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部分中包含primarykey列 .

  • 3

    您也可以尝试转储表,找到insert命令并对其进行编辑:

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

    --skip-extended-insert 每行为您提供一个插入命令 . 然后,您可以在您喜欢的文本编辑器中找到该行,解压缩命令并将主键更改为"default" .

  • 0

    我使用Grim的技术稍作改动:如果有人在寻找这个查询是因为由于主键问题而无法进行简单的查询:

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

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

    #1048 - Column 'primakey' cannot be null
    

    因此,在创建临时表之后,我将主键更改为可为空 .

    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;
    
  • 1

    此过程假定:

    • 你没有_duplicate_temp_table

    • 你的主键是int

    • 您可以访问create table

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

    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;
    
  • 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 .

  • 2

    以下部分内容是从本网站收集的 . 这就是我在具有任意数量字段的表中复制记录所做的事情:

    这也假设您在表的开头有一个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
    }
    
  • 3

    如果表的主键字段是自动增量字段,则可以对列使用查询 . 例如,名为 test_tbl 的表有3个字段 id, name, age . id 是主键字段和自动增量,因此您可以使用以下查询来复制该行:

    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=19 的重复行作为 id=20 插入 .

  • 1

    我可能会迟到,但我有一个类似的解决方案,对我有用 .

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

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

    我来寻找这个问题的解决方案(忘记了语法),最后我自己创建了查询 . 有趣的是,事情有时会发生 .

    问候

  • 0

    如果主键是自动增量,则只需指定除主键之外的每个字段 .

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

  • 0

    我更新@LeonardChallis 's solution as it didn'为我工作,没有其他人 . 我删除了临时表中的 WHERE 子句和 SET primaryKey = 0 ,因此MySQL会自动增加primaryKey

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

    这当然要复制表中的行 all .

  • 2

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

    • phpmyadmin 中,检查您想要的行复制

    • 在查询结果操作底部,单击 'Export'

    • 在下一页上检查 'Save as file' 然后单击 'Go'

    • 使用文本编辑器打开导出的文件,找到主要字段的值并将其更改为唯一的值 .

    • 返回 phpmyadmin 单击 'Import' 选项卡,找到要在 browse 下导入.sql文件的文件,单击 'Go' 并插入重复行 .

    如果您不知道 PRIMARY 字段是什么,请回顾 phpmyadmin 页面,单击 'Structure' 选项卡,在 'Indexes' 页面底部,它将显示 'Field' 具有 'Keyname''PRIMARY' .

    还有很长的路要走,但是如果你不想处理标记而只需要复制一行就可以了 .

  • 4

    我会在下面使用,

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

    对于necropost感到抱歉,但这是我在google上找到的,因为我发现这有用但有问题我想为其他任何挖掘它的人做出重要修改 .

    首先,我使用的是SQL Server,而不是MySQL,但我认为它的工作方式应该类似 . 我使用了Leonard Challis的解决方案,因为它最简单并满足了需求,但是这有一个问题 - 如果你只是拿PK并将其递增1然后如果你添加了其他记录会发生什么,因为有问题的行被添加了 . 我决定最好让系统处理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中会有类似的作用,但我无法测试,对不起

  • 0

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

    这假设主键是自动递增的,在主表中复制一行,并使用新的主表id创建链表数据的副本 .

    获取列名称的其他选项:
    -SHOW COLUMNS来自 tablename ; (列名:字段)
    -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__);
    }
    
  • -1

    max233肯定是在正确的轨道上,至少对于自动增量案例 . 但是,不要做ALTER TABLE . 只需将临时表中的自动增量字段设置为NULL即可 . 这将显示错误,但临时表中的所有字段的以下INSERT将发生,并且NULL自动字段将获得唯一值 .

  • 56

    创建一个表

    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;
    

    测试

    SELECT * FROM `sample_table`;
    
  • 0

    以下是我在网站上找到的答案描述如何进行上述操作1您可以在页面底部找到答案 . 基本上,您要做的是将要复制的行复制到内存中保存的临时表中 . 然后使用update更改主键号 . 然后,将其重新插入目标表 . 然后你放弃 table .

    这是它的代码:

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

    我创建了临时表rescueteam . 我复制了原始表fitnessreport4中的行 . 然后,我将临时表中的行的主键设置为null,以便我可以将其复制回原始表而不会出现Duplicate Key错误 . 我昨天晚上尝试了这段代码并且有效 .

  • 165

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

    SELECT * FROM table where primarykey=1
    

    然后在页面底部:

    enter image description here

    在哪里说“导出”只是导出,然后编辑csv文件以删除primarykey值,因此它为空,然后只需将其导入数据库,将在导入时分配新的主键 .

  • 10

    该解决方案显示上述工作对于所选行也是完美的 . 例如,我正在为我的nice2work项目创建演示行,这很有效完善 .

    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;";
    
  • 8

    具有更新字段和自动增量值的克隆行

    CREATE TEMPORARY TABLE `temp` SELECT * FROM `testing` WHERE id = 14;
    
    UPDATE `temp` SET id = (SELECT id FROM testing ORDER by id DESC LIMIT 1
     )+1, user_id = 252 ,policy_no = "mysdddd12" where id = 14;
    
    INSERT INTO `testing` SELECT * FROM `temp`;
    
    DROP TEMPORARY TABLE IF EXISTS `temp`;
    
  • 6

    只想发布我的PHP代码,因为我认为我收集列的方式比前面的例子更清晰 . 这也显示了如何轻松更改字段,在这种情况下添加字符串 . 但是,您也可以使用新添加的记录替换外键字段,以防您想要复制某些子记录 .

    // 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();
    

相关问题