Bagaimana cara menyalin baris dan menyisipkan dalam tabel yang sama dengan bidang peningkatan otomatis di MySQL?

233

Di MySQL saya mencoba menyalin baris dengan autoincrement column ID=1 dan memasukkan data ke tabel yang sama dengan baris baru column ID=2.

Bagaimana saya bisa melakukan ini dalam satu permintaan?

Navdroid
sumber

Jawaban:

351

Gunakan INSERT ... SELECT:

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

di mana c1, c2, ...semua kolom kecuali id. Jika Anda ingin secara eksplisit memasukkan dengan angka id2 maka sertakan dalam daftar kolom INSERT dan SELECT Anda:

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

Anda harus mengurus kemungkinan duplikat id2 dalam kasus kedua tentu saja.

mu terlalu pendek
sumber
1
Anda dapat secara programatik mendapatkan nama kolom menggunakan INFORMATION_SCHEMA ... Saya ingin tahu apakah Anda dapat melakukannya sebagai sub-kueri dan beberapa fungsi string? Hmmm ...
Yzmir Ramirez
1
@Yzmir: Anda akhirnya harus menggunakan SQL dinamis dan itu biasanya membutuhkan pembangunan prosedur tersimpan. Sepertinya lebih banyak masalah daripada nilainya ketika Anda harus memiliki daftar nama kolom berguna.
mu terlalu pendek
6
Setuju ... dari pengalaman saya setelah Anda pergi Prosedur Tersimpan Anda tidak kembali - Anda sudah menikah dengan database itu sekarang dan hanya menambah biaya setiap kali Anda ingin mengubah.
Yzmir Ramirez
11
@YzmirRamirez, Anda membuatnya terdengar seperti pernikahan pada dasarnya adalah hal yang buruk. :)
Prof. Falken
1
Bagaimana cara menambahkan satu nilai khusus dalam kolom dengan semua bidang lain yang disalin?
Manish Kumar
49

IMO, yang terbaik tampaknya menggunakan pernyataan sql hanya untuk menyalin baris itu, sementara pada saat yang sama hanya mereferensikan kolom yang harus dan ingin Anda ubah.

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;

Lihat juga av8n.com - Cara Mengkloning Catatan SQL

Manfaat:

  • Pernyataan SQL 2 hanya menyebutkan bidang yang perlu diubah selama proses kloning. Mereka tidak tahu tentang - atau peduli tentang - bidang lain. Bidang-bidang lain hanya mengikuti untuk perjalanan, tidak berubah. Ini membuat pernyataan SQL lebih mudah untuk ditulis, lebih mudah dibaca, lebih mudah dipelihara, dan lebih bisa dikembangkan.
  • Hanya pernyataan MySQL biasa yang digunakan. Tidak diperlukan alat atau bahasa pemrograman lain.
  • Catatan yang sepenuhnya benar dimasukkan your_tabledalam satu operasi atom.
parvus
sumber
3
Kelihatannya, bahwa trik yang bagus ini (saya menyukainya, tetapi tidak berhasil bagi saya) tidak berfungsi pada tabel yang berisi kolom TEKS / VARCHAR. Saya mencobanya dan mendapatkan: (1163): Jenis tabel yang digunakan tidak mendukung kolom BLOB / TEXT. Itu tentu saja membatasi penggunaan pada MySQL sangat banyak! Mungkin, bahwa di masa depan batas-batas ini dicabut atau pada sistem db lain itu berhasil, tetapi untuk saat ini benar-benar terbatas.
Juergen
Saya sangat suka penggunaan tabel sementara yang cerdas. Sangat berguna untuk tabel dengan banyak kolom!
Lasma
1
Terlihat bagus, tetapi ketika saya menjalankan query pertama di MySQL, saya mengerti Error Code: 1113. A table must have at least 1 column.
physicalattraction
3
Jawaban terbaik untuk banyak kolom. Tetapi SET id=NULLdapat menyebabkan kesalahan Column 'id' cannot be null. Harus diganti olehUPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
Modder
1
@ phisikicaltraksi Anda perlu memastikan dua baris pertama adalah satu pernyataan.
Samuurai
16

Katakanlah tabelnya user(id, user_name, user_email).

Anda dapat menggunakan kueri ini:

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)
Vijay
sumber
29
Anda harus selalu menentukan nama kolom saat menggunakan INSERT, jika tidak, Anda akan mendapatkan bug yang aneh dan menarik ketika skema Anda berubah.
mu terlalu pendek
2
Aneh dan menarik, memang. : D
sparkyShorts
Tidak berfungsi dengan sqlite. Result: near "SELECT": syntax error
kyb
10

Ini membantu dan mendukung kolom 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;
Petr Hladík
sumber
Dengan cara apa ini lebih baik daripada jawaban lain di sini?
Smar
3
Saya pikir itu cukup bagus jika Anda memiliki meja dengan 100 bidang. Kecuali mungkin ada batasan bukan nol pada id yang membuatnya gagal
Loïc Faure-Lacroix
Kode Kesalahan: 1136. Jumlah kolom tidak cocok dengan jumlah nilai pada baris 1
Oleksii Kyslytsyn
Ini jauh lebih baik jika Anda memiliki tabel dengan 100 kolom.
Tyler S. Loeper
Bukankah ini yang dikatakan parvus, bertahun-tahun sebelumnya?
ToolmakerSteve
7

Untuk solusi cepat dan bersih yang tidak mengharuskan Anda memberi nama kolom, Anda dapat menggunakan pernyataan yang disiapkan seperti dijelaskan di sini: https://stackoverflow.com/a/23964285/292677

Jika Anda membutuhkan solusi yang kompleks sehingga Anda bisa sering melakukan ini, Anda dapat menggunakan prosedur ini:

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

Anda dapat menjalankannya dengan:

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

Contohnya

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

PENOLAKAN: Solusi ini hanya untuk seseorang yang akan berulang kali menduplikasi baris di banyak tabel, sering. Ini bisa berbahaya di tangan pengguna nakal.

curmil
sumber
3

Anda juga dapat memasukkan '0' sebagai nilai untuk penambahan kolom, nilai yang benar akan digunakan ketika catatan dibuat. Ini jauh lebih mudah daripada tabel sementara.

Sumber: Menyalin baris di MySQL (lihat komentar kedua, oleh TRiG, ​​untuk solusi pertama, oleh Lore)

Tandai Pruce
sumber
1
Metode ini berfungsi dengan versi MySQL yang lebih baru ketika NULL tidak dapat diterima.
err
3

Banyak jawaban bagus di sini. Di bawah ini adalah contoh dari prosedur tersimpan yang saya tulis untuk menyelesaikan tugas ini untuk Aplikasi Web yang saya kembangkan:

-- 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
sumber
dalam versi saat ini MariaDB / pengaturan MySQL id = null memberikan # 1048 - Kolom 'id' tidak boleh nol, pengaturan id = 0 berfungsi;
shelbypereira
2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;
Programmer IR
sumber
3
Bagaimana ini lebih baik daripada jawaban lain di sini?
Smar
1
@smar imo lebih bersih untuk mengerti
Satbir Kira
2

Jika Anda dapat menggunakan MySQL Workbench, Anda dapat melakukan ini dengan mengklik kanan baris dan memilih 'Salin baris', lalu mengklik kanan baris kosong dan memilih 'Tempel baris', lalu mengubah ID, dan kemudian mengklik 'Terapkan'.

Salin baris:

masukkan deskripsi gambar di sini

Rekatkan baris yang disalin ke baris kosong:

masukkan deskripsi gambar di sini

Ubah ID:

masukkan deskripsi gambar di sini

Menerapkan:

masukkan deskripsi gambar di sini

Nathan Wailes
sumber
0

Saya mencari fitur yang sama tetapi saya tidak menggunakan MySQL. Saya ingin menyalin SEMUA bidang kecuali tentu saja kunci utama (id). Ini adalah permintaan sekali pakai, tidak untuk digunakan dalam skrip atau kode apa pun.

Saya menemukan jalan saya dengan PL / SQL tapi saya yakin IDE SQL lainnya akan melakukannya. Saya melakukan dasar

SELECT * 
FROM mytable 
WHERE id=42;

Kemudian ekspor ke file SQL di mana saya dapat menemukan

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

Saya baru saja mengeditnya dan menggunakannya:

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (mysequence.nextval, 2, 3, ..., 42);
SabineA
sumber
0

Saya cenderung menggunakan variasi dari apa yang terlalu pendek diposting:

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

Selama tabel memiliki bidang yang identik (kecuali kenaikan otomatis pada tabel log), maka ini berfungsi dengan baik.

Karena saya menggunakan prosedur tersimpan sedapat mungkin (untuk membuat hidup lebih mudah pada programmer lain yang tidak terlalu terbiasa dengan database), ini memecahkan masalah harus kembali dan memperbarui prosedur setiap kali Anda menambahkan bidang baru ke tabel.

Ini juga memastikan bahwa jika Anda menambahkan bidang baru ke tabel, bidang itu akan segera muncul di tabel log tanpa harus memperbarui kueri basis data Anda (kecuali tentu saja Anda memiliki beberapa yang menetapkan bidang secara eksplisit)

Peringatan: Anda akan ingin memastikan untuk menambahkan bidang baru ke kedua tabel pada saat yang sama sehingga urutan bidang tetap sama ... jika tidak, Anda akan mulai mendapatkan bug aneh. Jika Anda adalah satu-satunya yang menulis antarmuka database DAN Anda sangat berhati-hati maka ini berfungsi dengan baik. Jika tidak, tetap gunakan penamaan semua bidang Anda.

Catatan: Setelah dipikir-pikir, kecuali jika Anda mengerjakan proyek solo yang Anda yakin tidak akan membuat orang lain mengerjakannya, cantumkan semua nama bidang secara eksplisit dan perbarui laporan log Anda saat skema Anda berubah. Jalan pintas ini mungkin tidak sebanding dengan sakit kepala jangka panjang yang dapat ditimbulkannya ... terutama pada sistem produksi.

Privateer
sumber
0
Masukkan ke dalam `dbMyDataBase`.`tblMyTable` 
(
    `IdAutoincrement`, 
    `Column2`, 
    `Column3`, 
    `Column4` 
) 

PILIH 
    BATAL,  
    `Column2`, 
    `Column3`, 
    'CustomValue' AS Kolom4 
DARI `dbMyDataBase`.`tblMyTable` 
WHERE `tblMyTable`.`Column2` = 'UniqueValueOfTheKey' 
; 
/ * mySQL 5.6 * /
Wojciech Skibiński
sumber
3
Coba tambahkan beberapa penjelasan yang lebih terperinci, atau bagaimana ini memperluas jawaban yang lain
Azsgy
-1

Buang baris yang ingin Anda sql dan kemudian gunakan SQL yang dihasilkan, kurangi kolom ID untuk mengimpornya kembali.

Claire
sumber