Bagaimana kunci auto_increment ditangani dalam INSERT (SELECT * FROM ...)

12

Saya miliki table1dan table2di MySQL. Keduanya memiliki auto_incrementkunci utama id.

Jika skema tabel cocok dan saya melakukan INSERT INTO table1 (SELECT * FROM table2)apa yang terjadi sehubungan dengan baris baru yang dimasukkan table1? Apakah mereka mempertahankan idnilai - nilai lama mereka dan menghasilkan konflik ketika sebuah baris dari table1memiliki nilai yang sama id? Apakah nilai baru dihasilkan oleh auto_increment? Apakah ini tergantung pada mesin penyimpanan atau penguncian?

Thomas Johnson
sumber

Jawaban:

13

Anda bisa memasukkan ke dalam kolom kenaikan otomatis dan menentukan nilai. Ini baik; itu hanya menimpa generator kenaikan-otomatis.

Jika Anda mencoba untuk memasukkan nilai NULL atau 0 atau DEFAULT, atau jika Anda menghilangkan kolom kenaikan otomatis dari kolom dalam pernyataan INSERT Anda, ini akan mengaktifkan generator kenaikan otomatis.

Jadi, tidak masalah untuk INSERT INTO table1 SELECT * FROM table2(omong-omong, Anda tidak membutuhkan tanda kurung). Ini berarti bahwa nilai id di table2akan disalin kata demi kata, dan tidaktable1 akan menghasilkan nilai baru.

Jika Anda ingin table1 menghasilkan nilai baru, Anda tidak bisa melakukannya SELECT *. Anda menggunakan nol atau 0 untuk kolom id:

INSERT INTO table1 SELECT 0, col1, col2, col3, ... FROM table2;

Atau Anda menghilangkan kolom dari daftar kolom pernyataan INSERT dan daftar pilihan pernyataan SELECT:

-- No id in either case:
INSERT INTO table1 (col1, col2, col3) SELECT col1, col2, col3, ... FROM table2;

Sebelum Anda bertanya, tidak ada sintaks dalam SQL untuk "pilih * kecuali untuk satu kolom". Anda harus mengeja daftar lengkap nama kolom yang ingin Anda masukkan.

Bill Karwin
sumber
Apakah tidak ada opsi yang memungkinkan / melarang penyisipan 0 sebagai nilai? (Mengenai paragraf kedua Anda)
Sascha Rambeaud
1
Ya, SQL_MODE = NO_AUTO_VALUE_ON_ZERO , kalau tidak kita tidak akan pernah bisa memasukkan nilai nol literal ke dalam kolom AI. Jika Anda menggunakan mode SQL ini, NULL masih berfungsi untuk mengaktifkan generator AI, atau menghilangkan kolom yang berfungsi juga.
Bill Karwin
@ BillKarwin, Mengenai paragraf terakhir Anda, setelah mendapatkan subresult select * from table, apakah tidak ada cara untuk beroperasi pada subresult ini untuk menghapus kolom pertamanya?
Pacerier
@ Peracerier, jika saya mengerti benar, Anda bertanya apakah select *bisa berarti select * except for the first column. Jawabannya adalah tidak. select *selalu meminta semua kolom dari tabel itu. Jika Anda menginginkan subset, Anda harus mengeja kolom yang Anda inginkan.
Bill Karwin
@ BillKarwin, Hmm, saya berpikir untuk memutar meja untuk melakukan klausa vertikal di mana, kemudian memutar kembali misalnya select*from transpose(select*from(transpose(select*from table where Id=1))where col_name<>Id)atau mungkin lebih ringkas seperti select*from table where Id=1 and $col<>Id, bagaimana menurut Anda?
Pacerier
3

Id dari pilih akan menjadi nilai yang sama dimasukkan ke dalam tabel. Ini akan menghasilkan kesalahan jika Anda mencoba menduplikasi baris yang ada.

Bill Karwin: Sebelum Anda bertanya, tidak ada sintaks dalam SQL untuk "pilih * kecuali untuk satu kolom".

Ini dapat dicapai dengan beberapa kreativitas:

SET @sql = CONCAT('INSERT INTO <table> SELECT null, 
    ', (SELECT GROUP_CONCAT(COLUMN_NAME) 
    FROM information_schema.columns 
    WHERE table_schema = '<database>' 
    AND table_name = '<table>' 
    AND column_name NOT IN ('id')), ' 
from <table> WHERE id = <id>');  

PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

Ini akan menghasilkan baris baru mendapatkan id yang bertambah secara otomatis alih-alih id dari baris yang dipilih.

curmil
sumber
2
Pintar, tetapi bagi saya, itu dianggap sebagai mengeja daftar lengkap nama kolom yang ingin Anda masukkan.
Bill Karwin
1
Yah itu mysql secara otomatis mengejanya dibandingkan melakukannya secara manual. Jika Anda memiliki tabel dengan banyak kolom, itu akan mencegah Anda kehilangan satu atau salah mengeja beberapa.
curmil