On Duplicate Key Update sama dengan memasukkan

158

Saya telah mencari-cari tetapi tidak menemukan apakah itu mungkin.

Saya memiliki permintaan MySQL ini:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8)

Field id memiliki "indeks unik", jadi tidak mungkin ada dua. Sekarang jika id yang sama sudah ada dalam database, saya ingin memperbaruinya. Tetapi apakah saya benar-benar harus menentukan semua bidang ini lagi, seperti:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY UPDATE a=2,b=3,c=4,d=5,e=6,f=7,g=8

Atau:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY UPDATE a=VALUES(a),b=VALUES(b),c=VALUES(c),d=VALUES(d),e=VALUES(e),f=VALUES(f),g=VALUES(g)

Saya telah menentukan semua yang sudah ada di sisipan ...

Catatan tambahan, saya ingin menggunakan pekerjaan untuk mendapatkan ID!

id=LAST_INSERT_ID(id)

Saya harap seseorang dapat memberi tahu saya apa cara yang paling efisien.

Roy
sumber
9
AFAIK, metode ulangan setiap kolom, a=VALUES(a), b=VALUES(b), ...adalah cara yang harus Anda tempuh. Begitulah cara saya melakukannya untuk semua INSERT ON DUPLICATE KEY UPDATEpernyataan saya .
Valdogg21
4
Hanya untuk memperjelas, semua yang dinyatakan di sini adalah benar selama Anda memahami pertanyaan yang dijawab adalah: Haruskah Anda menyatakan kembali setiap kolom yang INGIN DIPERBARUI? Ya, jika Anda ingin menyisipkan atau memperbarui 8 kolom dalam tabel 25-kolom, Anda harus menyatakan 8 kolom dua kali - sekali di bagian masukkan dan satu kali di bagian pembaruan. (Anda dapat melewatkan kunci utama di bagian pembaruan, tetapi lebih mudah untuk melakukan praformat pada string "a = 1, b = 2, c = 3" dan menyematkannya dua kali.) Namun, Anda TIDAK harus menyatakan kembali 17 kolom yang tersisa. Anda tidak ingin berubah. Jika itu menjadi PEMBARUAN, mereka akan mempertahankan nilai-nilai yang ada.
Timberline
3
Saya menambahkan komentar itu karena pertanyaan dan jawaban membuat saya tidak yakin tentang kolom yang tidak disebutkan dengan jenis INSERT ini, yang kemudian saya uji setelah mengetahui apa yang harus diuji. INSERT ON DUPLICATE KEY UPDATE membuat kolom yang tidak disebutkan tidak berubah pada UPDATE tetapi memberi mereka nilai default pada INSERT. Dengan REPLACE INTO, kolom yang tidak disebutkan namanya selalu mendapatkan nilai default, tidak pernah nilai yang ada.
Timberline
1
Periksa stackoverflow.com/questions/2472229/… , saya pikir ada yang Anda cari
Chococroc

Jawaban:

82

The UPDATEpernyataan yang diberikan sehingga bidang yang lebih tua dapat diperbarui untuk nilai baru. Jika nilai lama Anda sama dengan nilai baru Anda, mengapa Anda perlu memperbaruinya?

Untuk misalnya. jika kolom Anda auntuk gsudah ditetapkan sebagai 2untuk 8; tidak perlu memperbarui lagi.

Atau, Anda dapat menggunakan:

INSERT INTO table (id,a,b,c,d,e,f,g)
VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY
    UPDATE a=a, b=b, c=c, d=d, e=e, f=f, g=g;

Untuk mendapatkan iddari LAST_INSERT_ID; Anda perlu menentukan aplikasi backend yang Anda gunakan untuk hal yang sama.

Untuk LuaSQL, a conn:getlastautoid()mengambil nilai.

hjpotter92
sumber
6
Itu hanya untuk contoh. Dalam kueri kehidupan nyata ada perbedaan. Pertanyaan saya cukup sederhana: Apakah saya benar-benar perlu menentukan semua bidang (dan nilai dalam contoh pertama saya) jika sama dengan di sisipan? Saya hanya ingin memasukkan semua atau jika ada kecocokan nilai yang unik: perbarui semua.
Roy
1
"Catatan tambahan, aku ingin menggunakan pekerjaan untuk mendapatkan ID juga!"
Agamemnus
1
@ Presdin, Sejauh yang saya tahu itu hanya gula sintaksis. Secara pribadi, saya belum pernah melihat orang menggunakan a = VALUES (a), b = VALUES (b), dll. Mungkin Anda dapat menetapkan beberapa nilai ke kolom? Tidak yakin mengapa Anda tidak hanya menggabungkan data sebelumnya.
DuckPuncher
54
Jika tabel tblsudah memiliki baris (1,10) maka: INSERT INTO tbl(id, a) VALUES(1,2) ON DUPLICATE KEY UPDATE a=VALUES(a)akan menetapkan a = 2 . Sementara INSERT INTO tbl(id, a) VALUES(1,2) ON DUPLICATE KEY UPDATE a=aakan menetapkan = 10
Bệi Việt Thành
2
Kenapa semua upvotes? Ini tidak bekerja. Seperti yang ditunjukkan oleh @ Bùi Việt Thành, tidak menggunakan a=apembaruan apa pun. (Pertanyaan dalam pertanyaan awal juga tidak benar-benar memperbarui apa pun, tetapi pembaruan tampaknya seperti yang dimaksudkan OP.)
Roger Dueck
41

Ada ekstensi khusus MySQL ke SQL yang mungkin Anda inginkan - REPLACE INTO

Namun tidak berfungsi sama seperti 'ON DUPLICATE UPDATE'

  1. Ini menghapus baris lama yang berbenturan dengan baris baru dan kemudian menyisipkan baris baru. Selama Anda tidak memiliki kunci utama pada tabel itu akan baik-baik saja, tetapi jika Anda melakukannya, maka jika ada tabel lain yang merujuk kunci utama

  2. Anda tidak bisa mereferensikan nilai di baris lama sehingga Anda tidak bisa melakukan yang setara

    INSERT INTO mytable (id, a, b, c) values ( 1, 2, 3, 4) 
    ON DUPLICATE KEY UPDATE
    id=1, a=2, b=3, c=c + 1;

Saya ingin menggunakan pekerjaan di sekitar untuk mendapatkan ID!

Itu seharusnya bekerja - last_insert_id () harus memiliki nilai yang benar selama kunci utama Anda bertambah secara otomatis.

Namun seperti yang saya katakan, jika Anda benar-benar menggunakan kunci utama di tabel lain, REPLACE INTOmungkin tidak akan dapat Anda terima, karena menghapus baris lama yang bentrok melalui kunci unik.

Seseorang menyarankan sebelum Anda dapat mengurangi mengetik dengan melakukan:

INSERT INTO `tableName` (`a`,`b`,`c`) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE `a`=VALUES(`a`), `b`=VALUES(`b`), `c`=VALUES(`c`);
Danack
sumber
Jadi, saya tidak bisa tetap menggunakan kunci utama sebelum replace intopermintaan?
Roy
Tidak - baris itu dihapus dan baris baru dibuat, yang akan memiliki kunci utama baru.
Danack
tidakkah ini akan memperlambat proses pada dataset besar dan seperti mengimpor csv dengan 100K atau lebih baris?
Muhammad Omer Aslam
24

Tidak ada cara lain, saya harus menentukan semuanya dua kali. Pertama untuk menyisipkan, kedua dalam kasus pembaruan.

Roy
sumber
9
Ini tidak benar dan seharusnya bukan jawaban yang diterima. Jawaban dari @Danack adalah jawaban yang benar.
Wayne Workman
2
Anda harus membaca kembali pertanyaan @WayneWorkman, ini adalah jawaban yang benar.
Roy
24

Ini solusi untuk masalah Anda:

Saya sudah mencoba menyelesaikan masalah seperti masalah Anda & saya ingin menyarankan untuk menguji dari aspek sederhana.

Ikuti langkah-langkah ini: Belajar dari solusi sederhana.

Langkah 1: Buat skema tabel menggunakan SQL Query ini:

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(30) NOT NULL,
  `password` varchar(32) NOT NULL,
  `status` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `no_duplicate` (`username`,`password`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;

Tabel <code> pengguna </code> dengan data

Langkah 2: Buat indeks dua kolom untuk mencegah duplikat data menggunakan SQL Query berikut:

ALTER TABLE `user` ADD INDEX no_duplicate (`username`, `password`);

atau, Buat indeks dua kolom dari GUI sebagai berikut: Buat indeks dari GUI Pilih kolom untuk membuat indeks Indeks tabel <code> pengguna </code>

Langkah 3: Perbarui jika ada, masukkan jika tidak menggunakan pertanyaan berikut:

INSERT INTO `user`(`username`, `password`) VALUES ('ersks','Nepal') ON DUPLICATE KEY UPDATE `username`='master',`password`='Nepal';

INSERT INTO `user`(`username`, `password`) VALUES ('master','Nepal') ON DUPLICATE KEY UPDATE `username`='ersks',`password`='Nepal';

Tabel <code> pengguna </code> setelah menjalankan kueri di atas


sumber
1
Terima kasih untuk penelusuran ini - buat saya mengerti, sangat dihargai, terima kasih!
Michael Nilsson
FYI menyimpan kata sandi dalam teks biasa adalah ide yang buruk, seperti mencoba mencegah duplikat kata sandi di tingkat basis data.
OrangeDog
10

Jika Anda dapat menggunakan bahasa skrip untuk menyiapkan kueri SQL, Anda bisa menggunakan kembali pasangan bidang = nilai dengan menggunakan SETalih-alih (a,b,c) VALUES(a,b,c).

Contoh dengan PHP:

$pairs = "a=$a,b=$b,c=$c";
$query = "INSERT INTO $table SET $pairs ON DUPLICATE KEY UPDATE $pairs";

Tabel contoh:

CREATE TABLE IF NOT EXISTS `tester` (
  `a` int(11) NOT NULL,
  `b` varchar(50) NOT NULL,
  `c` text NOT NULL,
  UNIQUE KEY `a` (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Chris
sumber
4
Anda harus melarikan diri dari nilai-nilai Anda atau menjalankan pernyataan yang disiapkan dengan nilai-nilai Anda.
Chinoto Vokro
1
@ChinotoVokro - Saya setuju. Ini hanya menyajikan "bagaimana Anda bisa" dan bahkan tidak menggunakan fungsi kueri dalam contoh.
Chris
1
Ini adalah alternatif yang baik untuk menentukan array kunci dan array nilai. Terima kasih.
Mark Carpenter Jr
5

Anda mungkin ingin mempertimbangkan untuk menggunakan REPLACE INTOsintaks, tetapi berhati-hatilah, pada duplikat kunci PRIMARY / UNIK, itu MENGHAPUS baris dan SERI yang baru.

Anda tidak perlu menentukan ulang semua bidang. Namun, Anda harus mempertimbangkan pengurangan kinerja yang mungkin (tergantung pada desain meja Anda).

Peringatan:

  • Jika Anda memiliki kunci utama AUTO_INCREMENT, itu akan diberikan yang baru
  • Indeks mungkin perlu diperbarui
Matej
sumber
ada pelanggaran kendala jika indeks juga merupakan kunci asing untuk tabel lain, itu dipicu oleh hapus bagian.
user3290180
4

Saya tahu ini sudah terlambat, tetapi saya berharap seseorang akan terbantu dengan jawaban ini

INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

Anda dapat membaca tutorial di bawah ini di sini:

https://mariadb.com/kb/en/library/insert-on-duplicate-key-update/

http://www.mysqltutorial.org/mysql-insert-or-update-on-duplicate-key-update/

Galang Piliang
sumber
Jawaban yang bagus. Tetapi penggunaan VALUES () untuk merujuk ke baris baru sudah tidak digunakan pada MySQL 8.0.20 . Pendekatan baru, terinci di tautan, adalah dengan menggunakan alias untuk baris. Dalam contoh ini, aliasnya adalah new:INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6) AS new ON DUPLICATE KEY UPDATE c = new.a+new.b;
user697473
@ user697473 Saya mendapatkan kesalahan: "Anda memiliki kesalahan dalam sintaks SQL Anda; periksa manual yang sesuai dengan versi server MariaDB Anda untuk sintaks yang tepat untuk digunakan di dekat 'SEBAGAIMANA SAJA DI DUPLICATE KUNCI PEMBARUAN a = new.a'" , dan permintaan saya berfungsi (kecuali ketika kunci duplikat terjadi, jelas) sebelum saya menerapkan klausa ini. Ada ide?
aaron
@ Harun - maaf, tidak ada ide bagus. MySQL 8.0.20 baru dirilis pada akhir April; mungkin MariaDB belum menyusul. Itu bisa menjelaskan mengapa itu memberi Anda kesalahan.
user697473
@ user697473 Ya saya sebenarnya baru saja mencoba metode a = VALUES (a) dalam jawaban asli dan berhasil, terima kasih.
Aaron
-7

Anda dapat menggunakan sisipkan abaikan untuk kasus seperti itu, itu akan diabaikan jika mendapat catatan duplikat SISIPKAN LUAR BIASA ...; - tanpa KUNCI DUPLIKASI

pitu
sumber
Saya ingin memasukkannya saat tidak ada, perbarui lagi. Jangan abaikan itu.
Roy
mengapa Anda ingin memperbaruinya jika Anda memperbarui dengan nilai sebelumnya / yang sama, jika nilai baru maka tidak apa-apa dengan itu, jika tidak memasukkan abaikan pekerjaan untuk itu
pitu
2
Kemungkinan besar karena nilainya dapat berubah, dan ia ingin membuat catatan jika tidak ada, tetapi perbarui catatan yang ada jika ada (dengan perubahan) tanpa overhead dari pulang pergi kembali ke aplikasi dan kemudian kembali ke database lagi.
mopsyd