В MySQL я могу скопировать одну строку, чтобы вставить в ту же таблицу? - PullRequest
143 голосов
/ 28 октября 2010
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;

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

Ответы [ 25 ]

0 голосов
/ 19 мая 2016

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

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

CREATE TEMPORARY TABLE rescueteam ENGINE = ВЫБОР ПАМЯТИ * ИЗ fitnessreport4 ГДЕ rID = 1; # 1строка пострадала.ОБНОВЛЕНИЕ rescueteam SET rID = Ноль, ГДЕ rID = 1; повреждена строка # 1. ВСТАВИТЬ INTO fitnessreport4 ВЫБРАТЬ * ИЗ rescueteam; затронута строка # 1DROP TABLE rescueteam # MySQL вернул пустой набор результатов (т. Е. Ноль
строк).

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

0 голосов
/ 18 октября 2015

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

    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 голосов
/ 29 сентября 2013

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

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

Другие варианты получения имен столбцов:- ПОКАЗАТЬ КОЛОННЫ ОТ tablename;(Название столбца: Поле)-ОПИСАТЬ tablename (Название столбца: Поле)-ВЫБРАТЬ имя столбца FROM information_schema.columns ГДЕ table_name = 'tablename' (Имя столбца: имя_ столбца)

//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__);
}
0 голосов
/ 04 декабря 2013

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

0 голосов
/ 31 января 2014

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