Yinelenen Anahtar Güncellemesinde ekleme ile aynı


158

Etrafı araştırdım ama mümkün olup olmadığını bulamadım.

Bu MySQL sorgusu var:

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

Alan kimliğinin "benzersiz bir dizini" vardır, bu nedenle bunlardan iki tanesi olamaz. Şimdi aynı kimlik veritabanında zaten varsa, güncellemek istiyorum. Ama gerçekten tüm bu alanları tekrar belirtmek zorunda mıyım?

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

Veya:

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)

Zaten ekte olan her şeyi belirttim ...

Ek bir not, kimlik almak için bu işi kullanmak istiyorum!

id=LAST_INSERT_ID(id)

Umarım biri bana en etkili yolun ne olduğunu söyleyebilir.


9
Her sütunu yeniden düzenleme yöntemi olan AFAIK, a=VALUES(a), b=VALUES(b), ...gitmeniz gereken yoldur. Tüm INSERT ON DUPLICATE KEY UPDATEifadelerim için böyle yapıyorum .
Valdogg21

4
Açıklığa kavuşturmak için, burada belirtilen her şey, yanıtlanan soruyu anladığınız sürece doğrudur: GÜNCELLEMEK İSTEDİĞİNİZ her sütunu yeniden belirtmeniz gerekir mi? Evet, 25 sütunlu bir tabloya 8 sütun eklemek veya güncellemek istiyorsanız, 8 sütunu iki kez belirtmeniz gerekir - bir kez ekleme bölümünde ve bir kez de güncelleme bölümünde. (Güncelleme bölümündeki birincil anahtarı atlayabilirsiniz, ancak bir "a = 1, b = 2, c = 3" dizesini önceden biçimlendirmek ve iki kez gömmek en kolay yöntemdir.) Ancak, kalan 17 sütunu yeniden oturtmak GEREKMEZ değiştirmek istemiyorsun. Bir GÜNCELLEME haline gelirse, mevcut değerlerini korurlar.
Timberline

3
Bu yorumu ekledim, çünkü sorular ve cevaplar, tam olarak neyi test edeceğimizi öğrendikten sonra test ettiğim bu tür INSERT ile sözü edilmeyen sütunlar hakkında emin değilim. DUPLICATE KEY UPDATE'E EKLE, UPDATE'te sözü edilmeyen sütunları değiştirmeden bırakır, ancak INSERT üzerinde varsayılan değerleri verir. REPLACE INTO ile, sözü edilmeyen sütunlar her zaman varsayılan değerleri alır, asla mevcut değerleri almaz.
Timberline

1
Stackoverflow.com/questions/2472229/… 'ı kontrol edin , aradığınız şey olduğunu düşünüyorum
Chococroc

Yanıtlar:


82

UPDATEEski alanlar yeni değere göre güncellenir böylece deyim verilir. Eski değerleriniz yenileriyle aynıysa, neden her durumda güncellemeniz gerekir?

Örneğin. Sütunlarınızın eğer aiçin gzaten olarak ayarlanmıştır 2için 8; yeniden güncellemeye gerek yoktur.

Alternatif olarak şunları kullanabilirsiniz:

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;

Almak için idgelen LAST_INSERT_ID; bunun için kullandığınız arka uç uygulamasını belirtmeniz gerekir.

LuaSQL conn:getlastautoid()için bir değer alır.


6
Sadece örnek için. Gerçek hayat sorgusunda farklılıklar vardır. Benim sorum sessiz basit: Gerçekten tüm alanları (ve ilk örneğimdeki değerleri) eklemenizle aynı ise belirtmem gerekiyor mu? Sadece hepsini eklemek istiyorum veya benzersiz bir değer eşleşmesi varsa: hepsini güncelle.
Roy

1
Diyerek şöyle devam etti: "Ek bir not, kimliği almak için buradaki işi de kullanmak istiyorum!"
Agamemnus

1
@Tresdin, Anlayabildiğim kadarıyla sadece sözdizimsel şeker. Şahsen, a = VALUES (a), b = VALUES (b) vb. Kullanan birini hiç görmedim. Belki sütuna birden fazla değer atayabilirsiniz? Verileri neden önceden birleştirmeyeceğinizden emin değilsiniz.
DuckPuncher

54
Tabloda tblzaten satır (1,10) varsa: INSERT INTO tbl(id, a) VALUES(1,2) ON DUPLICATE KEY UPDATE a=VALUES(a)a = 2 ayarlayacaktır . Süre INSERT INTO tbl(id, a) VALUES(1,2) ON DUPLICATE KEY UPDATE a=aa = 10
Bệi Việt Fotoğraf

2
Neden tüm oylar? Bu çalışmıyor. @ Bùi Việt Thành'un işaret ettiği gibi, a=agüncellemeleri hiçbir şey kullanmadı . (Orijinal sorudaki sorgular aslında hiçbir şeyi güncellemez, ancak bir güncelleme OP'nin istediği gibi görünüyor.)
Roger Dueck

41

SQL'in MySQL'e özel bir uzantısı olabilir. REPLACE INTO

Ancak 'ÜÇÜNCÜ GÜNCELLEME GÜNCELLEMESİ' ile tam olarak aynı şekilde çalışmaz

  1. Yeni satırla çakışan eski satırı siler ve yeni satırı ekler. Tablonun üzerinde iyi olacak bir birincil anahtarınız olmadığı sürece, ancak yaparsanız, başka bir tablo bu birincil anahtara başvuruyorsa

  2. Eski satırlardaki değerlere başvuramazsınız, böylece

    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;

Kimlik almak için bu işi kullanmak istiyorum!

Bu işe yaramalı - birincil anahtarınız otomatik olarak artırıldığı sürece last_insert_id () doğru değere sahip olmalıdır.

Ancak dediğim gibi, bu birincil anahtarı diğer tablolarda kullanırsanız, REPLACE INTObenzersiz anahtarla çakışan eski satırı sildiğinden muhtemelen sizin için kabul edilemez.

Başka bir kişi daha önce yazarak bazı yazımları azaltabileceğinizi önerdi :

INSERT INTO `tableName` (`a`,`b`,`c`) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE `a`=VALUES(`a`), `b`=VALUES(`b`), `c`=VALUES(`c`);

Yani, bir replace intosorgu önce birincil anahtar ile sopa olamaz ?
Roy

Hayır - bu satır silinir ve yeni bir birincil anahtar içeren yeni bir satır oluşturulur.
Danack

Bu büyük veri kümelerinde süreci yavaşlatır ve 100K veya daha fazla satırla csv'leri içe aktarmayı sever mi?
Muhammed Ömer Aslam

24

Başka yolu yok, her şeyi iki kez belirtmem gerekiyor. İlk olarak ekleme için, ikincisi güncelleme durumunda.


9
Bu yanlıştır ve kabul edilen cevap olmamalıdır. @ Danack'in cevabı doğru cevaptır.
Wayne Workman

2
@WayneWorkman sorusunu tekrar okumalısınız, bu doğru cevap.
Roy

24

İşte sorununuza bir çözüm:

Seninki gibi sorunu çözmeye çalıştım ve basit bir açıdan test etmeyi önermek istiyorum.

Şu adımları izleyin: Basit çözümden öğrenin.

Adım 1: Bu SQL Sorgusunu kullanarak bir tablo şeması oluşturun :

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;

Verileri içeren bir <code> kullanıcı </code> tablosu

Adım 2: Aşağıdaki SQL Sorgusu'nu kullanarak yinelenen verileri önlemek için iki sütundan oluşan bir dizin oluşturun :

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

veya GUI'den aşağıdaki gibi iki sütundan oluşan bir dizin oluşturun : GUI'den dizin oluştur Dizin oluşturmak için sütunları seçin <code> kullanıcı </code> tablosunun dizinleri

3. Adım: Varsa güncelleyin, aşağıdaki sorguları kullanmıyorsanız ekleyin :

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

Yukarıdaki sorguyu çalıştırdıktan sonra <code> kullanıcı </code> tablosu


1
Bu izlenecek yol için teşekkür ederim - beni anladı, çok takdir etti, teşekkür ederim!
Michael Nilsson

Şifreleri düz metinde saklamak, veritabanı düzeyinde yinelenen şifreleri önlemeye çalışırken korkunç bir fikirdir.
OrangeDog

10

SQL sorgularınızı hazırlamak için bir komut dosyası dili kullanabiliyorsanız, field = value çiftlerini SETbunun yerine kullanarak yeniden kullanabilirsiniz (a,b,c) VALUES(a,b,c).

PHP ile bir örnek:

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

Örnek tablo:

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;

4
Değerlerinizden kaçmalı veya değerlerinizle birlikte hazırlanmış bir ifade çalıştırmalısınız.
Chinoto Vokro

1
@ChinotoVokro - Kabul ediyorum. Bu sadece bir "nasıl yapabileceğinizi" gösterir ve örnekte herhangi bir sorgu fonksiyonu bile kullanmaz.
Chris

1
Bu, bir anahtar dizisi ve bir değer dizisi belirtmek için iyi bir alternatiftir. Teşekkürler.
Mark Carpenter Jr

5

Sen kullanarak düşünebilirsiniz REPLACE INTOsözdizimi, ancak yinelenen İLKÖĞRETİM / EŞSİZ tuşunun üzerine uyarılır, bu SILME satır ve UçLaRı yenisini.

Tüm alanları yeniden belirtmeniz gerekmez. Ancak, olası performans düşüşünü dikkate almalısınız (tablo tasarımınıza bağlıdır).

Uyarılar:

  • AUTO_INCREMENT birincil anahtarınız varsa, ona yeni bir anahtar verilir
  • Dizinlerin muhtemelen güncellenmesi gerekecek

eğer indeks başka bir tablo için yabancı bir anahtar ise, bir kısıtlama ihlali söz konusudur.
user3290180

4

Geç olduğunu biliyorum, ama umarım birisi bu cevaba yardımcı olur

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

Aşağıdaki öğreticiyi buradan okuyabilirsiniz:

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

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


İyi cevap. Ancak, yeni satırlara başvurmak için VALUES () kullanımı MySQL 8.0.20'den itibaren kullanımdan kaldırılmıştır . Bağlantıda ayrıntıları verilen yeni yaklaşım, satır için bir takma ad kullanmaktır. Bu örnekte, takma ad 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 Şu hatayı alıyorum: "SQL sözdiziminizde bir hata var; MariaDB sunucu sürümünüze karşılık gelen kılavuzu, 'AS new ON DUPLICATE KEY UPDATE a = new.a' yakınında kullanılacak doğru sözdizimi için kontrol edin" ve bu maddeyi uygulamadan önce sorgum çalışıyordu (açıkça yinelenen anahtarlar dışında). Herhangi bir fikir?
aaron

@aaron - üzgünüm, harika bir fikir yok. MySQL 8.0.20 Nisan ayı sonunda piyasaya çıktı; belki MariaDB henüz yakalanmadı. Bu size neden bir hata verdiğini açıklayabilir.
user697473

@ user697473 Evet aslına bakarsanız orijinal cevapta a = VALUES (a) yöntemini denedim ve çalıştı, yine de teşekkürler.
aaron

-7

böyle bir durumda insert ignore kullanabilirsiniz, yinelenen kayıtlar alırsa yoksay INSERT IGNORE ...; - ÜST DÜZEY ANAHTAR olmadan


Mevcut olmadığında eklemek istedim, başka güncelleyin. Yoksaymayın.
Roy

neden önceki / aynı değerle güncelliyorsanız güncellemek istersiniz, eğer onun yeni bir değer varsa onunla tamam, eğer
eklemezseniz

2
Büyük olasılıkla değerler değişebileceğinden ve yoksa bir kayıt oluşturmak istiyor, ancak uygulamaya geri dönüş ve daha sonra veritabanına geri dönüşü olmadan (değişikliklerle) mevcut bir kaydı güncelliyor tekrar.
mopsyd
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.