Дублировать / копировать записи в той же таблице MySQL


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

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

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 77

9 ответов:

то, как я обычно делаю это, использует временную таблицу. Это, вероятно, не вычислительно эффективно, но, кажется, работает нормально! Здесь я дублирую запись 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;

надеюсь, что это работает нормально для вас!

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

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

вы точно знаете, что дубликат ключа сработает, поэтому вы можете заранее выбрать MAX(ID)+1:

INSERT INTO invoices SELECT MAX(ID)+1, ... other fields ... FROM invoices AS iv WHERE iv.ID=XXXXX 

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

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

поздний ответ я знаю, но это все еще общий вопрос, я хотел бы добавить еще один ответ, что он работал для меня, используя только одну строку 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, в противном случае, вы можете добавить 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;

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

у меня есть аналогичная проблема, и это то, что я делаю

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

Была 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

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

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

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

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

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

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

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

небольшое изменение, основное отличие заключается в том, чтобы установить поле первичного ключа ("varname") в null, которое выдает предупреждение, но работает. Установив первичный ключ в значение 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;