В MySQL я могу скопировать одну строку для вставки в ту же таблицу?

insert into table select * from table where primarykey=1

Я просто хочу скопировать одну строку для вставки в ту же таблицу (т.е. хочу дублировать существующую строку в таблице), но я хочу сделать это, не перебирая все столбцы после "select", потому что в этой таблице слишком много столбцов.

Но когда я это сделаю, я получаю сообщение об ошибке:

Дублировать запись 'xxx' для клавиши 1

Я могу справиться с этим, создав другую таблицу с теми же столбцами, что и временный контейнер для записи, которую я хочу скопировать:

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;

Есть ли более простой способ решить эту проблему?

Ответ 1

Я использовал технику Леонарда Чаллиса с несколькими изменениями:

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 в этом случае) в мое временное имя таблицы.

Ответ 2

Обновление 07/07/2014 - Ответ, основанный на моем ответе от Grim..., является лучшим решением, поскольку оно улучшает мое решение ниже, поэтому я бы предложил использовать это.

Вы можете сделать это без перечисления всех столбцов со следующим синтаксисом:

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;

Вы можете изменить первичный ключ другим способом.

Ответ 3

Я предполагаю, что вы хотите, чтобы новая запись имела новый primarykey? Если primarykey - AUTO_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

... где 567 - новое значение для primarykey.

Ответ 4

У вас почти было это с первым запросом, вам просто нужно указать столбцы, таким образом вы можете исключить свой первичный ключ во вставке, который будет вводить автоматическое увеличение, которое, вероятно, будет иметь в таблице, чтобы автоматически создать новый первичный ключ для ввода.

Например, измените это:

insert into table select * from table where primarykey=1

Для этого:

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

Просто не включайте столбец primarykey в список столбцов для INSERT или для частей SELECT запроса.

Ответ 5

Вы также можете попробовать сбросить таблицу, найти команду вставки и отредактировать ее:

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

--skip-extended-insert дает вам одну команду вставки для каждой строки. Затем вы можете найти строку в своем любимом текстовом редакторе, извлечь команду и изменить первичный ключ на "default".

Ответ 6

Эта процедура предполагает, что:

  • у вас нет _duplicate_temp_table
  • ваш первичный ключ - int
  • у вас есть доступ к созданию таблицы

Конечно, это не идеально, но в некоторых (возможно, большинстве) случаях он будет работать.

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, '[email protected]');
        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;

Ответ 7

Это может быть достигнуто с некоторым творчеством:

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;

Это приведет к тому, что новая строка получит автоматически увеличенный идентификатор вместо идентификатора из выбранной строки.

Ответ 8

Если поле основного ключа вашей таблицы является полем автоматического увеличения, вы можете использовать запрос с столбцами. Например, ваша таблица с именем 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.

Ответ 9

Некоторые из перечисленных ниже были удалены с этого сайта. Это то, что я сделал, чтобы дублировать запись в таблице с любым количеством полей:

Это также предполагает, что у вас есть поле 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
}

Ответ 10

Возможно, я опаздываю, но у меня есть аналогичное решение, которое сработало для меня.

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

Таким образом, мне не нужно создавать временную таблицу и т.д. Когда строка копируется в ту же таблицу, можно легко использовать функцию Max(PK)+1.

Я искал решение этого вопроса (забыл синтаксис), и в итоге я сделал свой собственный запрос. Забавно, как все складывается несколько раз.

Привет

Ответ 11

Если основной ключ является автоматическим приращением, просто укажите каждое поле, кроме первичного ключа.

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

Ответ 12

Я обновил решение @LeonardChallis, поскольку он не работал у меня, как никто другой. Я удалил предложения WHERE и SET primaryKey = 0 в таблице temp, поэтому MySQL автоматически увеличивает сам primaryKey

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

Это, конечно, дублирует строки all в таблице.

Ответ 13

Я бы использовал ниже,

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

Ответ 14

строка клона с полями обновления и значением автоматического увеличения

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`;

Ответ 15

Мне просто нужно было это сделать, и это было мое решение для руководства:

  • В phpmyadmin проверьте строку, которую вы хотите скопировать.
  • В нижней части окна результатов запроса нажмите "Экспорт"
  • На следующей странице отметьте "Сохранить как файл" , затем нажмите "Перейти"
  • Откройте экспортированный файл с помощью текстового редактора, найдите значение первичного поля и измените его на нечто уникальное.
  • Вернитесь в phpmyadmin, перейдите на вкладку "Импорт" , найдите файл для импорта файла .sql в просмотре, нажмите 'Go', а дублирующаяся строка должна быть вставлена.

Если вы не знаете, что такое PRIMARY, посмотрите на страницу phpmyadmin, перейдите на вкладку "Структура" и внизу страницы "Индексы" покажет вам, у кого "Поле" имеет "Имя ключа" значение PRIMARY '.

Вид длинного пути, но если вы не хотите иметь дело с разметкой и просто нужно дублировать одну строку, вы идете.

Ответ 16

Я использовал технику Grim с небольшим изменением: если кто-то ищет этот запрос, потому что не может выполнить простой запрос из-за проблемы с первичным ключом:

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

С моей установкой MySql 5.6.26 ключ не имеет значения NULL и создает ошибку:

#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;

Ответ 17

Это решение, показанное выше, отлично подходит для выбранных строк. Например, я создаю демонстрационные строки для моего проекта 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;";

Ответ 18

Извините за некропость, но это то, с чем я столкнулся с google, и так как я нашел это полезным, но проблемным, я хотел внести важный вклад для кого-то, кто его раскопал.

Во-первых, я использую SQL Server, а не MySQL, но я думаю, что он должен работать аналогичным образом. Я использовал решение Леонарда Чаллиса, потому что он был простейшим и удовлетворял потребность, однако есть проблема с этим - если вы просто возьмете ПК и увеличьте его на 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, но я не могу проверить это, извините

Ответ 19

Я знаю, это старый вопрос, но вот еще одно решение:

Это дублирует строку в основной таблице, предполагая, что первичный ключ является автоматическим приращением, и создает копии данных связанных таблиц с новым идентификатором главной таблицы.

Другие варианты получения имен столбцов:
-SHOW COLUMNS FROM 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__);
}

Ответ 20

max233, безусловно, был на правильном пути, по крайней мере, для случая автоинкремента. Однако не выполняйте ALTER TABLE. Просто установите поле автоинкремента в поле временная таблица до NULL. Это приведет к ошибке, но следующий INSERT все поля во временной таблице будут выполняться, и поле "NULL auto" будет получено уникальное значение.

Ответ 21

Создать таблицу

    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`;

Ответ 22

Вот ответ, который я нашел онлайн на этом сайте Описывает, как это сделать 1 Вы можете найти ответ в нижней части страницы. В основном, то, что вы делаете, это скопировать строку, которая будет скопирована во временную таблицу, хранящуюся в памяти. Затем вы изменяете номер первичного ключа, используя обновление. Затем вы снова вставляете его в целевую таблицу. Затем вы бросаете стол.

Это код для него:

СОЗДАТЬ ВРЕМЕНУ ТАБЛИЦУ rescueteam ДВИГАТЕЛЬ = ВЫБОР ПАМЯТИ * ОТ fitnessreport4 ГДЕ rID = 1; # 1 затронута строка. UPDATE rescueteam SET rID = Null WHERE rID = 1; # row affected.INSERT INTO fitnessreport4 SELECT * FROM rescueteam; повреждена строка # 1. DROP TABLE rescueteam # MySQL возвращает пустой набор результатов (т.е. Нуль     строки).

Я создал временную таблицу rescueteam. Я скопировал строку из моего исходного таблицы fitnessreport4. Затем я устанавливаю первичный ключ для строки во временной таблице равным нулю, поэтому я могу скопировать ее обратно в исходную таблицу, не получив Duplicate Key error. Вчера вечером я попробовал этот код, и он сработал.

Ответ 23

Для очень простого решения вы можете использовать PHPMyAdmin для экспорта строки в виде файла CSV, а затем просто импортировать измененный CSV файл. Редактирование столбца ID/primarykey для отображения значения до его импорта.

SELECT * FROM table where primarykey=1

Затем в нижней части страницы:

введите описание изображения здесь

Где указано "Экспорт", просто экспортируйте, а затем отредактируйте файл csv, чтобы удалить значение основной клавиши, поэтому он пуст, а затем просто импортирует его в базу данных, при импорте будет назначен новый первичный ключ.

Ответ 24

Я использовал в своей базе данных Koha для вставки повторяющихся элементов с префиксом 'C' в столбце штрих-кода:

INSERT INTO items ('biblionumber', 'biblioitemnumber', 'barcode', 'dateaccessioned' ) SELECT 'biblionumber', 'biblioitemnumber',  CONCAT('C','barcode'), 'dateaccessioned' FROM 'items' WHERE barcode='14832';

Ответ 25

Просто хочу опубликовать свой фрагмент кода 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();