Як скопіювати рядок і вставити в ту саму таблицю з полем для автоматичного збільшення в MySQL?


233

В MySQL я намагаюся скопіювати рядок з Autoincrement column ID=1 і вставити дані в одній таблиці в якості нового рядка з column ID=2.

Як я можу це зробити за допомогою одного запиту?

Відповіді:


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

У idдругому випадку, звичайно, вам доведеться подбати про можливий дублікат 2.


1
Ви могли б програмно отримувати назви стовпців за допомогою INFORMATION_SCHEMA ... Цікаво, чи можна це зробити як підзапит та деякі функції рядка?
Гммм

1
@Yzmir: Вам, звичайно, доведеться використовувати динамічний SQL, і зазвичай це вимагає побудови збереженої процедури. Здається, більше клопоту, ніж варто, коли у будь-якому випадку вам слід мати список зручних імен стовпців.
mu занадто короткий

6
Погоджено ... з мого досвіду, коли ви переходите до Збереженої процедури, ви не повернетесь - ви зараз одружені з цією базою даних і просто збільшуєте витрати, коли хочете змінити.
Ізмір Рамірес

11
@YzmirRamirez, ти вважаєш, що шлюб по суті є поганою справою. :)
Проф. Фолкен

1
Як додати одне спеціальне значення у стовпчик із усіма іншими скопійованими полями?
Маніш Кумар

49

ІМО, мабуть, найкраще використовувати оператори 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.
physicalattraction

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, інакше ви отримаєте дивні та цікаві помилки, коли ваша схема зміниться.
mu занадто короткий

2
Дивно і цікаво, справді. : D
sparkyShorts

Не працює з sqlite. Result: near "SELECT": syntax error
киб

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
Олексій Кислицин

Це набагато краще, якщо у вас є таблиця зі 100 стовпцями.
Тайлер С. Лопер

Хіба це не те, про що говорив Парвус, роками раніше?
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

ВІДМОВА ВІДПОВІДАЛЬНІСТЬ: Це рішення призначене лише для тих, хто буде багаторазово дублювати рядки у багатьох таблицях. Це може бути небезпечно для рук шахрая.


3

Ви також можете передати "0" як значення стовпця для автоматичного збільшення, правильне значення буде використано при створенні запису. Це набагато простіше, ніж тимчасові таблиці.

Джерело: Копіювання рядків у MySQL (див. Другий коментар, TRiG, ​​до першого рішення, Лоре)


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

у поточній версії настройки MariaDB / MySQL id = null дає # 1048 - стовпець 'id' не може бути нульовим, встановлення id = 0 працює;
shelbypereira

2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;

3
Чим це краще, ніж інші відповіді?
Смар

1
@smar imo це зрозуміліше
Satbir Kira

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

0

Я схильний використовувати варіант того, що розміщено занадто коротко:

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

Поки таблиці мають однакові поля (виключаючи автоматичний приріст таблиці журналів), це добре працює.

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

Це також гарантує, що якщо ви додасте нові поля до таблиці, вони почнуть з’являтися в таблиці журналів негайно, не потребуючи оновлення запитів у вашій базі даних (якщо, звичайно, у вас є такі, які встановлюють поле явно)

Попередження: Ви захочете додати нові поля в обидві таблиці одночасно, щоб порядок поля залишався однаковим ... інакше ви почнете отримувати непарні помилки. Якщо ви єдиний, хто пише інтерфейси бази даних І ви дуже обережні, то це прекрасно працює. Інакше дотримуйтесь назв усіх своїх полів.

Примітка. По-друге, якщо ви не працюєте над сольним проектом, ви впевнені, що інші люди, які працюють над ним, не будуть чітко перераховувати всі назви полів та оновлювати ваші журнали, коли ваша схема змінюється. Цей ярлик, мабуть, не вартує тривалого головного болю, який він може викликати ... особливо у виробничій системі.


0
ВСТУПУЙТЕ в `dbMyDataBase`.` TblMyTable` 
(
    `IdAutoincrement`, 
    `Колона2`, 
    `Колона3`, 
    `Колона4` 
) 

ВИБІРИ 
    НУЛЬ,  
    `Колона2`, 
    `Колона3`, 
    AS колонка4 "CustomValue" 
ВІД `dbMyDataBase`.` TblMyTable` 
WHERE `tblMyTable`.`Column2` = 'UniqueValueOfTheKey' 
; 
/ * mySQL 5.6 * /

3
Спробуйте додати дещо більш детальне пояснення, або як це розширюється на інші відповіді
Azsgy

-1

Вивантажте рядок, який ви хочете sql, а потім використовуйте створений SQL за вирахуванням стовпця ідентифікатора, щоб імпортувати його назад.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.