ÇİFT ANAHTARDA MySQL - son eklenen kimlik?


132

Şu sorguya sahibim:

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE a=1

Ek veya güncellemenin kimliğini istiyorum. Bunu elde etmek için genellikle ikinci bir sorgu çalıştırırım, çünkü insert_id () işlevinin güncellenmiş kimliği değil, yalnızca 'eklenen' kimliği döndürdüğüne inanıyorum.

INSERT / UPDATE yapmanın ve iki sorgu çalıştırmadan satırın kimliğini almanın bir yolu var mı?


3
Tahmin etmek yerine, neden kendiniz test etmiyorsunuz? Yukarıdaki düzenlemedeki SQL işe yarıyor ve benim testim sayesinde, INSERT IGNORE kullanarak veya önce bir kopya olup olmadığını görmek için bir ekleme hatasını yakalamaktan daha hızlı.
Michael Fenwick

4
UYARI: Önerilen çözüm çalışır, ancak auto_increment değeri, ekleme olmasa bile artmaya devam eder. Yinelenen anahtar sık ​​sık meydana geliyorsa, alter table tablename AUTO_INCREMENT = 0;kimlik değerlerinde büyük boşlukları önlemek için yukarıdaki sorgudan sonra çalıştırmak isteyebilirsiniz .
Frank Forte

Yanıtlar:


175

Bu sayfaya göz atın: https://web.archive.org/web/20150329004325/https://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Sayfanın altında o MySQL işlevine bir ifade ileterek LAST_INSERT_ID kimliğini güncellemeler için nasıl anlamlı hale getirebileceğinizi açıklarlar.

MySQL dokümantasyon örneğinden:

Bir tablo AUTO_INCREMENT sütunu içeriyorsa ve INSERT ... UPDATE bir satır eklerse, LAST_INSERT_ID () işlevi AUTO_INCREMENT değerini döndürür. İfade bunun yerine bir satırı güncellerse, LAST_INSERT_ID () anlamlı değildir. Ancak, LAST_INSERT_ID (ifade) kullanarak bu sorunu çözebilirsiniz. İd'nin AUTO_INCREMENT sütunu olduğunu varsayalım. LAST_INSERT_ID () öğesini güncellemeler için anlamlı hale getirmek üzere aşağıdaki gibi satırlar ekleyin:

INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;

2
O sayfaya bakarken bir şekilde bunu kaçırdım. Dolayısıyla güncelleme kısmı şu şekilde görünür: UPDATE id = LAST_INSERT_ID (id) Ve bu harika çalışıyor. Teşekkürler!
thekevinscott

7
Php fonksiyonunun mysql_insert_id () her iki durumda da doğru değeri döndürdüğü söylenir : php.net/manual/en/function.mysql-insert-id.php#59718 .
jayarjo

2
@PetrPeller - MySQL'in iç kısımlarına bakmadan, muhtemelen bir değer üreteceği anlamına gelir, ancak bu değer az önce çalıştırdığınız sorgu ile ilgili değildir. Başka bir deyişle, hata ayıklaması zor olan bir problem.
Jason

13
5.1.12'den sonra bu sözde artık gerekli değildir, ancak bugün buna bir istisna buldum. Bir otomatik artırma pk'niz ve e-posta adresinde benzersiz bir anahtarınız varsa ve e-posta adresini temel alan 'yinelenen güncellemede' tetikleyiciler varsa, last_insert_id'nin güncellenen satırın otomatik artırma değeri OLMAYACAĞINI unutmayın. En son eklenen otomatik artış değeri gibi görünüyor. Bu çok büyük bir fark yaratıyor. Çözüm burada gösterilenle aynıdır, yani güncelleme sorgusunda id = LAST_INSERT_ID (id) kullanmak için.
sckd

1
5.5'te @ sckd'nin yorumu hala geçerli.
e18r

37

Kesin olarak, orijinal sorgu buysa:

INSERT INTO table (a) VALUES (0)
 ON DUPLICATE KEY UPDATE a=1

ve 'id', otomatik artırmalı birincil anahtardır, bunun çalışan çözüm olacağı anlamına gelir:

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), a=1

Hepsi burada: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Bir tablo AUTO_INCREMENT sütunu içeriyorsa ve INSERT ... UPDATE bir satır eklerse, LAST_INSERT_ID () işlevi AUTO_INCREMENT değerini döndürür. İfade bunun yerine bir satırı güncellerse, LAST_INSERT_ID () anlamlı değildir. Ancak, LAST_INSERT_ID (ifade) kullanarak bu sorunu çözebilirsiniz. İd'nin AUTO_INCREMENT sütunu olduğunu varsayalım.


7
Evet, söyledikleriniz için kabul edilen yanıta bakın. 3 yıllık gönderileri canlandırmaya gerek yok. Yine de çabanız için teşekkürler.
Fancypants

1
@tombom bu yanıtı göndermemin tek nedeni kabul edilen cevabın doğru olmaması - güncellenecek bir şey yoksa işe yaramayacak.
Aleksandar Popovic

2

Eğer kayıt varsa, esasen bir silme / ekleme olan DEĞİŞTİR'e bakabilirsiniz. Ancak bu, varsa otomatik artış alanını değiştirir ve bu da diğer verilerle ilişkileri bozabilir.


1
Ah evet - önceki kimliklerden kurtulmayacak bir şey arıyorum
thekevinscott

Bu aynı zamanda başka bir ilgili verinin silinmesine de neden olabileceği için tehlikeli olabilir (kısıtlamalarla).
Serge


1

ON DUPLICATE ANAHTAR GÜNCELLEME id = LAST_INSERT_ID (id) birincil anahtarı 1 artırdığında bir sorunla karşılaştım. Böylece oturumdaki bir sonraki girişin kimliği 2 artırılacak


0

Kayda değer ve bu bariz olabilir (ancak yine de burada açıklık getirmek için söyleyeceğim), DEĞİŞTİR'in yeni verilerinizi eklemeden önce mevcut eşleşen satırı ortadan kaldıracaktır. ON DUPLICATE ANAHTAR GÜNCELLEME yalnızca belirttiğiniz sütunları günceller ve satırı korur.

Gönderen manuel :

DEĞİŞTİR, tam olarak INSERT gibi çalışır, ancak tablodaki eski bir satır, PRIMARY KEY veya UNIQUE dizini için yeni bir satırla aynı değere sahipse, eski satır yeni satır eklenmeden önce silinir.


0

Otomatik artış kullanırsanız mevcut çözümler çalışır. Kullanıcının bir önek tanımlayabildiği ve diziyi 3000'de yeniden başlatması gereken bir durumum var. Bu çeşitli önek nedeniyle, last_insert_id'i eklemeler için boş yapan autoincrement'i kullanamıyorum. Bunu şu şekilde çözdüm:

INSERT INTO seq_table (prefix, id) VALUES ('$user_prefix', LAST_INSERT_ID(3000)) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id + 1);
SELECT LAST_INSERT_ID();

Önek varsa, onu artırır ve last_insert_id'yi doldurur. Önek yoksa, öneki 3000 değeriyle ekler ve last_insert_id'yi 3000 ile doldurur.

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.