Как скопировать строку и вставить в ту же таблицу с автоинкрементным полем в MySQL?

233

В MySQL я пытаюсь скопировать строку с автоинкрементом column ID=1 и вставить данные в ту же таблицу, что и новая строка с column ID=2.

Как я могу сделать это в одном запросе?

Navdroid
источник

Ответы:

351

Используйте INSERT ... SELECT:

insert into your_table (c1, c2, ...)
select c1, c2, ...
from your_table
where id = 1

где c1, c2, ...все столбцы, кроме id. Если вы хотите явно вставить со значением id2, включите его в список столбцов INSERT и в свой SELECT:

insert into your_table (id, c1, c2, ...)
select 2, c1, c2, ...
from your_table
where id = 1

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

мю слишком коротка
источник
1
Тогда вы могли бы программно получить имена столбцов, используя INFORMATION_SCHEMA ... Интересно, вы могли бы сделать это как подзапрос и некоторые строковые функции? Хммм ...
Измир Рамирес
1
@Yzmir: В конечном итоге вам придется использовать динамический SQL, а для этого обычно требуется создание хранимой процедуры. Похоже, больше хлопот, чем стоит, когда вам все равно нужен список имен столбцов.
Му слишком короткая
6
Согласитесь ... по моему опыту, как только вы перейдете к хранимой процедуре, вы не вернетесь - вы теперь женаты на этой базе данных и просто увеличиваете расходы, когда хотите изменить.
Измир Рамирес
11
@YzmirRamirez, ты говоришь так, будто брак - это плохо. :)
Проф. Фалькен,
1
Как добавить одно пользовательское значение в столбце со всеми другими скопированными полями?
Маниш Кумар
49

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

CREATE TEMPORARY TABLE temp_table ENGINE=MEMORY

SELECT * FROM your_table WHERE id=1;
UPDATE temp_table SET id=NULL; /* Update other values at will. */

INSERT INTO your_table SELECT * FROM temp_table;
DROP TABLE temp_table;

Смотрите также av8n.com - Как клонировать запись SQL

Преимущества:

  • В операторах SQL 2 упоминаются только поля, которые необходимо изменить в процессе клонирования. Они не знают или не заботятся о других областях. Остальные поля просто остаются неизменными. Это облегчает написание операторов SQL, их легче читать, легче поддерживать и расширяемо.
  • Используются только обычные операторы MySQL. Никаких других инструментов или языков программирования не требуется.
  • Полностью правильная запись вставляется your_tableв одну атомарную операцию.
Парвус
источник
3
Кажется, этот хороший трюк (он мне понравился, но у меня он не работал) не работает с таблицами, содержащими столбцы TEXT / VARCHAR. Я попробовал и получил: (1163): Используемый тип таблицы не поддерживает столбцы BLOB / TEXT. Это, конечно, очень сильно ограничивает использование MySQL! Может быть, в будущем эти ограничения будут отменены или на других db-системах это сработает, но пока это действительно ограничено.
Юрген
Мне очень нравится умное использование временной таблицы. Так полезно для таблиц с кучей столбцов!
Ласма
1
Выглядит хорошо, но когда я запускаю первый запрос в MySQL, я получаю Error Code: 1113. A table must have at least 1 column.
физическая
3
Лучший ответ для многих столбцов. Но SET id=NULLможет вызвать ошибку Column 'id' cannot be null. Должен быть замененUPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
Моддер
1
@physicalattraction вы должны убедиться, что первые две строки - это одно утверждение.
Самуурай
16

Скажи, что стол есть user(id, user_name, user_email).

Вы можете использовать этот запрос:

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)
Виджай
источник
29
Вы должны всегда указывать имена столбцов при использовании INSERT, иначе вы получите странные и интересные ошибки, когда ваша схема изменится.
Му слишком короткая
2
Странно и интересно, действительно. : D
sparkyShorts
Не работает с sqlite. Result: near "SELECT": syntax error
kyb
10

Это помогло и поддерживает столбцы BLOB / TEXT.

CREATE TEMPORARY TABLE temp_table
AS
SELECT * FROM source_table WHERE id=2;
UPDATE temp_table SET id=NULL WHERE id=2;
INSERT INTO source_table SELECT * FROM temp_table;
DROP TEMPORARY TABLE temp_table;
USE source_table;
Петр Гладик
источник
Как это лучше, чем другие ответы здесь?
Смар
3
Я думаю, это очень хорошо, если у вас есть таблица с 100 полями. За исключением того, что может быть ненулевое ограничение для идентификатора, что делает его неудачным
Loïc Faure-Lacroix
Код ошибки: 1136. Количество столбцов не соответствует количеству значений в строке 1
Алексей Кислицын
Это намного лучше, если у вас есть таблица с сотнями столбцов.
Тайлер С. Лопер
Разве это не то, что сказал Парвус, много лет назад?
ToolmakerSteve
7

Для быстрого, чистого решения, которое не требует именования столбцов, вы можете использовать подготовленный оператор, как описано здесь: https://stackoverflow.com/a/23964285/292677

Если вам нужно сложное решение, чтобы вы могли делать это часто, вы можете использовать эту процедуру:

DELIMITER $$

CREATE PROCEDURE `duplicateRows`(_schemaName text, _tableName text, _whereClause text, _omitColumns text)
SQL SECURITY INVOKER
BEGIN
  SELECT IF(TRIM(_omitColumns) <> '', CONCAT('id', ',', TRIM(_omitColumns)), 'id') INTO @omitColumns;

  SELECT GROUP_CONCAT(COLUMN_NAME) FROM information_schema.columns 
  WHERE table_schema = _schemaName AND table_name = _tableName AND FIND_IN_SET(COLUMN_NAME,@omitColumns) = 0 ORDER BY ORDINAL_POSITION INTO @columns;

  SET @sql = CONCAT('INSERT INTO ', _tableName, '(', @columns, ')',
  'SELECT ', @columns, 
  ' FROM ', _schemaName, '.', _tableName, ' ',  _whereClause);

  PREPARE stmt1 FROM @sql;
  EXECUTE stmt1;
END

Вы можете запустить его с:

CALL duplicateRows('database', 'table', 'WHERE condition = optional', 'omit_columns_optional');

Примеры

duplicateRows('acl', 'users', 'WHERE id = 200'); -- will duplicate the row for the user with id 200
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts'); -- same as above but will not copy the created_ts column value    
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts,updated_ts'); -- same as above but also omits the updated_ts column
duplicateRows('acl', 'users'); -- will duplicate all records in the table

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Это решение предназначено только для тех, кто часто будет дублировать строки во многих таблицах. Это может быть опасно в руках мошенника.

curmil
источник
3

Вы также можете передать «0» в качестве значения для столбца для автоматического увеличения, правильное значение будет использовано при создании записи. Это намного проще, чем временные таблицы.

Источник: Копирование строк в MySQL (см. Второй комментарий от TRiG, ​​к первому решению от Lore)

Марк Прус
источник
1
Этот метод работает с более новыми версиями MySQL, когда NULL недопустим.
эээ
3

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

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON

-- Create Temporary Table
SELECT * INTO #tempTable FROM <YourTable> WHERE Id = Id

--To trigger the auto increment
UPDATE #tempTable SET Id = NULL 

--Update new data row in #tempTable here!

--Insert duplicate row with modified data back into your table
INSERT INTO <YourTable> SELECT * FROM #tempTable

-- Drop Temporary Table
DROP TABLE #tempTable
RBILLC
источник
в текущей версии MariaDB / MySQL установка id = null дает # 1048 - столбец «id» не может быть нулевым, установка id = 0 работает;
Шелбыперейра
2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;
IR.Programmer
источник
3
Как это лучше, чем другие ответы здесь?
Смар
1
@ Смар Имо, это чище понять
Сатбир Кира
2

Если вы можете использовать MySQL Workbench, вы можете сделать это, щелкнув правой кнопкой мыши по строке и выбрав «Копировать строку», затем щелкнув правой кнопкой мыши пустую строку и выбрав «Вставить строку», затем изменив идентификатор, а затем нажав «Применить».

Скопируйте строку:

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

Вставьте скопированную строку в пустую строку:

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

Изменить идентификатор:

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

Подать заявление:

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

Натан Уэйлс
источник
0

Я искал ту же функцию, но я не использую MySQL. Я хотел скопировать ВСЕ поля, кроме, конечно, первичного ключа (id). Это был одноразовый запрос, который нельзя использовать ни в одном скрипте или коде.

Я нашел свой путь с PL / SQL, но я уверен, что подойдет любая другая SQL IDE. Я сделал базовый

SELECT * 
FROM mytable 
WHERE id=42;

Затем экспортируйте его в файл SQL, где я мог бы найти

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (1, 2, 3, ..., 42);

Я только отредактировал это и использовал это:

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (mysequence.nextval, 2, 3, ..., 42);
SabineA
источник
0

Я склонен использовать вариант того, что мю слишком коротко опубликовано:

INSERT INTO something_log
SELECT NULL, s.*
FROM something AS s
WHERE s.id = 1;

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

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

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

Предупреждение: вы должны убедиться, что добавили все новые поля в обе таблицы одновременно, чтобы порядок полей не изменился ... в противном случае вы начнете получать странные ошибки. Если вы единственный, кто пишет интерфейсы базы данных, и вы очень осторожны, тогда это работает хорошо. В противном случае придерживайтесь имен всех ваших полей.

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

капер
источник
0
INSERT INTO `dbMyDataBase`.tblMyTable` 
(
    `IdAutoincrement`, 
    `Column2`, 
    `Column3`, 
    `Column4` 
) 

ВЫБРАТЬ 
    НОЛЬ,  
    `Column2`, 
    `Column3`, 
    'CustomValue' AS Column4 
FROM `dbMyDataBase``tblMyTable` 
ГДЕ `tblMyTable``Column2` = 'UniqueValueOfTheKey' 
; 
/ * MySQL 5.6 * /
Войцех Скибински
источник
3
Попробуйте добавить более подробное объяснение или как это распространяется на другие ответы
Azsgy
-1

Дамп строки, которую вы хотите sql, а затем используйте сгенерированный SQL, за исключением столбца ID, чтобы импортировать его обратно.

Claire
источник