Дублирование / копирование записей в той же таблице MySQL - PullRequest
83 голосов
/ 08 апреля 2009

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

У меня есть этот запрос:

INSERT INTO invoices
    SELECT * FROM invoices AS iv WHERE iv.ID=XXXXX
    ON DUPLICATE KEY UPDATE ID = (SELECT MAX(ID)+1 FROM invoices)

проблема в том, что это просто меняет ID строки вместо копирования строки. Кто-нибудь знает, как это исправить?

// edit: я хотел бы сделать это без ввода всех имен полей, поскольку имена полей могут меняться со временем.

Ответы [ 9 ]

127 голосов
/ 29 мая 2010

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

CREATE TEMPORARY TABLE tmp SELECT * FROM invoices WHERE id = 99;

UPDATE tmp SET id=100 WHERE id = 99;

INSERT INTO invoices SELECT * FROM tmp WHERE id = 100;

Надеюсь, у вас все хорошо!

79 голосов
/ 10 ноября 2011

Ответ Алекса требует некоторой осторожности (например, блокировка или транзакция) в мультиклиентских средах.

Предполагая, что поле AUTO ID является первым в таблице (обычный случай), мы можем использовать неявное сделки.

    CREATE TEMPORARY TABLE tmp SELECT * from invoices WHERE ...;
    ALTER TABLE tmp drop ID; # drop autoincrement field
    # UPDATE tmp SET ...; # just needed to change other unique keys
    INSERT INTO invoices SELECT 0,tmp.* FROM tmp;
    DROP TABLE tmp;

Из документов MySQL:

Использование AUTO_INCREMENT: Вы также можете явно присвоить NULL или 0 столбцу для генерации порядковых номеров.

11 голосов
/ 12 апреля 2013

Ваш подход хорош, но проблема в том, что вы используете "*" вместо перечисления имен полей. Если вы поместите все имена столбцов, кроме первичного ключа, ваш скрипт будет работать как charm для одной или нескольких записей.

INSERT INTO invoices (iv.field_name, iv.field_name,iv.field_name ) SELECT iv.field_name, iv.field_name,iv.field_name FROM invoices AS iv WHERE iv.ID=XXXXX

11 голосов
/ 08 апреля 2009

Вы точно знаете, что сработает DUPLICATE KEY, поэтому вы можете заранее выбрать MAX (ID) +1:

INSERT INTO invoices SELECT MAX(ID)+1, ... other fields ... FROM invoices AS iv WHERE iv.ID=XXXXX 
7 голосов
/ 30 января 2017

Поздний ответ, я знаю, но это все еще общий вопрос, я хотел бы добавить еще один ответ, который сработал для меня, с использованием только одной строки insert into, и я думаю, что это прямо, без создания любая новая таблица (поскольку это может быть проблема с разрешениями CREATE TEMPORARY TABLE):

INSERT INTO invoices (col_1, col_2, col_3, ... etc)
  SELECT
    t.col_1,
    t.col_2,
    t.col_3,
    ...
    t.updated_date,
  FROM invoices t;

Решение работает для AUTO_INCREMENT столбца идентификатора, в противном случае вы можете добавить ID столбец к выражению:

INSERT INTO invoices (ID, col_1, col_2, col_3, ... etc)
  SELECT
    MAX(ID)+1,
    t.col_1,
    t.col_2,
    t.col_3,
    ... etc ,
  FROM invoices t;

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

3 голосов
/ 12 июля 2015

Я просто хотел расширить великолепный ответ Алекса, чтобы он был уместен, если вам захочется дублировать весь набор записей:

SET @x=7;
CREATE TEMPORARY TABLE tmp SELECT * FROM invoices;
UPDATE tmp SET id=id+@x;
INSERT INTO invoices SELECT * FROM tmp;

Я просто должен был сделать это и нашел ответ Алекса идеальной отправной точкой !. Конечно, вы должны установить @x на самый высокий номер строки в таблице (я уверен, что вы можете получить это с помощью запроса). Это полезно только в этой очень специфической ситуации, поэтому будьте осторожны, если не хотите дублировать все строки. Отрегулируйте математику по мере необходимости.

2 голосов
/ 13 марта 2012

У меня похожая проблема, и это то, чем я занимаюсь

insert into Preguntas  (`EncuestaID`, `Tipo` , `Seccion` , `RespuestaID` , `Texto` )  select '23', `Tipo`, `Seccion`, `RespuestaID`, `Texto` from Preguntas where `EncuestaID`= 18

Begu Preguntas:

CREATE TABLE IF NOT EXISTS `Preguntas` (
  `ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `EncuestaID` int(11) DEFAULT NULL,
  `Tipo` char(5) COLLATE utf8_unicode_ci DEFAULT NULL,
  `Seccion` int(11) DEFAULT NULL,
  `RespuestaID` bigint(11) DEFAULT NULL,
  `Texto` text COLLATE utf8_unicode_ci ,
  PRIMARY KEY (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=522 ;

Итак, ID автоматически увеличивается, и я также использую фиксированное значение ('23') для `EncuestaID

1 голос
/ 24 марта 2010

Мне это тоже нужно было; Мое решение состояло в том, чтобы использовать SQLYOG (бесплатная версия) для экспорта нужной записи в виде SQL (создает вставку).

Затем я вручную отредактировал это, чтобы удалить идентификатор, так как его нужно сгенерировать автоматически, а затем скопировал вставку в SQLYog для ее выполнения. Это было безболезненно. Я думаю, что многие другие графические интерфейсы MySQL могут сделать это также.

Это дает мне запись, которую я могу использовать для тестирования в реальной системе.

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

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

Небольшое отклонение, основное отличие состоит в том, чтобы установить поле первичного ключа ("имя_папки") в ноль, что выдает предупреждение, но работает Если для первичного ключа задано значение NULL, автоинкремент работает при вставке записи в последний оператор.

Этот код также очищает предыдущие попытки и может быть запущен более одного раза без проблем:

DELETE FROM `tbl` WHERE varname="primary key value for new record";
DROP TABLE tmp;
CREATE TEMPORARY TABLE tmp SELECT * FROM `tbl` WHERE varname="primary key value for old record";
UPDATE tmp SET varname=NULL;
INSERT INTO `tbl` SELECT * FROM tmp;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...