MySQL'de son güncellenen satırın kimliği nasıl elde edilir?


135

PHP kullanarak MySQL'de son güncellenen satırın kimliğini nasıl alabilirim?


2
mysqli_insert_id ($ bağlantı) tam olarak son güncellenen satırın kimliğini döndürecektir. Bu işlevi projelerimde de aynı amaçla kullanıyorum. Hem eşzamanlı hem de eşzamansız sorgularda kullanabilirsiniz. Kodunuza $ lastupdated_row_id = mysqli_insert_id ($ link) ekleyin ve sizin için çalışacaktır.
Naeem Ul Wahhab

1
Güncellerseniz satırın kimliğini zaten bilmiyor musunuz? Sanırım yapmadığın bazı durumlar olmalı.
JCharette

1
Güncelleme sorgunuzda muhtemelen bir where cümlesi kullanıyorsunuz, neden seçme sorgusunda aynı where cümlesini kullanamıyorsunuz? UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1?
Salman A

Yanıtlar:


236

Bu soruna bir cevap buldum :)

SET @update_id := 0;
UPDATE some_table SET column_name = 'value', id = (SELECT @update_id := id)
WHERE some_other_column = 'blah' LIMIT 1; 
SELECT @update_id;

DÜZENLEME aefxx tarafından

Bu teknik, bir güncelleme ifadesinden etkilenen her satırın kimliğini almak için daha da genişletilebilir:

SET @uids := null;
UPDATE footable
   SET foo = 'bar'
 WHERE fooid > 5
   AND ( SELECT @uids := CONCAT_WS(',', fooid, @uids) );
SELECT @uids;

Bu, tüm kimliklerin virgülle birleştirildiği bir dize döndürür.


6
Bunun 0 olumlu oy aldığına ve OP'nin hiç sormadığı mysql_insert_id () yorumunun 13 olduğuna inanamıyorum. Teşekkürler Pomyk, akıllıca bir numara!
Jaka Jančar

1
Bir WHEREcümleniz olduğundan , bir WHEREsonraki sorgunuzda aynı cümleyi kullanabilirsinizSELECT id FROM footable WHERE fooid > 5
Salman A

4
Belki herkes bunu anlar, ancak mysql_query () kullanırsanız; bunu üç farklı aramaya bölmelisiniz, ancak işe yarayacaktır.
rael_kid

8
Değişken kullanmaya bile gerek yok. LAST_INSERT_ID()bir sonraki çağrı tarafından döndürülen değeri ayarlayacak bir argümanı kabul edebilir LAST_INSERT_ID(). Örneğin: UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';. Şimdi, SELECT LAST_INSERT_ID();güncellenmiş kimliği döndürecektir. Daha fazla ayrıntı için newtover'ın cevabına bakın.
Joel

3
@SteveChilds Newtover'ın sorusuna yorum yapıyordum ve anlattığınız tuzağa bir çözüm eklemek istiyorum. GÜNCELLEME bir şey yok, bu setleri 0'a LAST_INSERT_ID: UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);. Ancak birden fazla kimliği almadığı için bu yanıt daha üstündür.
martinczerwi

33

Hm, cevaplar arasında en kolay çözümü görmeme şaşırdım.

Diyelim ki, tablodaki item_idbir tamsayı kimlik sütunu itemsve satırları aşağıdaki ifadeyle güncelliyorsunuz:

UPDATE items
SET qwe = 'qwe'
WHERE asd = 'asd';

Ardından, ifadeden hemen sonra etkilenen en son satırı öğrenmek için, ifadeyi aşağıdaki şekilde biraz güncellemelisiniz:

UPDATE items
SET qwe = 'qwe',
    item_id=LAST_INSERT_ID(item_id)
WHERE asd = 'asd';
SELECT LAST_INSERT_ID();

Yalnızca gerçekten değiştirilmiş satırı güncellemeniz gerekiyorsa, satırdaki verilerin değişip değişmeyeceğini kontrol ederek LAST_INSERT_ID aracılığıyla item_id için koşullu bir güncelleme eklemeniz gerekir.


3
Çoklu kullanıcı güvenlidir çünkü birden çok istemci UPDATE deyimini yayınlayabilir ve kendi sıra değerlerini kendi sıra değerlerini oluşturan diğer istemcileri etkilemeden veya onlardan etkilenmeden SELECT deyimiyle (veya mysql_insert_id ()) alabilir. Gereğince dev.mysql.com/doc/refman/5.0/en/...
brutuscat

1
Bu, item_id'yi son eklenen kayda ayarlamaz mı?
arleslie

2
@arleslie, brutuscat'in yukarıdaki yorumunda yer alan dokümanların bağlantısını takip ederseniz, olmayacağını göreceksiniz. Bu, tam olarak durum için tasarlanan davranıştır.
newtover

1
Bu gerçekten doğru cevap. Sorgu biraz sezgisel görünse de, bu tam olarak MySQL Belgelerinin söylediği şeydir.
Timothy Zorn

3
Sorgu kafanızı karıştırıyorsa, LAST_INSERT_ID (ifade) UPDATE çağrısı için ifade değerini döndüreceğinden, bunu şu şekilde de kullanabilirsiniz:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
martinczerwi

14

Bu resmi olarak basit ama dikkat çekici derecede sezgiseldir. Eğer yapıyorsan:

update users set status = 'processing' where status = 'pending'
limit 1

Şununla değiştirin:

update users set status = 'processing' where status = 'pending'
and last_insert_id(user_id) 
limit 1

Eklenmesi last_insert_id(user_id)halinde wheremaddeye MySQL anlatıyor set FOUND sıranın kimliğine iç değişken. Bunu last_insert_id(expr)beğenmek için bir değer ilettiğinizde, bu değeri döndürür, ki buradaki gibi kimliklerde her zaman pozitif bir tam sayıdır ve bu nedenle her zaman true olarak değerlendirilir, where cümlesine asla müdahale etmez. Bu yalnızca bir satır gerçekten bulunursa işe yarar, bu nedenle etkilenen satırları kontrol etmeyi unutmayın. Daha sonra kimliği birden çok yolla alabilirsiniz.

MySQL last_insert_id()

LAST_INSERT_ID () 'yi çağırmadan diziler oluşturabilirsiniz, ancak işlevi bu şekilde kullanmanın faydası, kimlik değerinin sunucuda otomatik olarak oluşturulan son değer olarak tutulmasıdır. Çoklu kullanıcı güvenlidir çünkü birden çok istemci UPDATE deyimini yayınlayabilir ve kendi sıra değerlerini oluşturan diğer istemcileri etkilemeden veya onlardan etkilenmeden SELECT deyimiyle (veya mysql_insert_id ()) kendi sıra değerini alabilir.

MySQL mysql_insert_id()

Önceki INSERT veya UPDATE deyimiyle AUTO_INCREMENT sütunu için oluşturulan değeri döndürür. AUTO_INCREMENT alanı içeren bir tabloya INSERT deyimi uyguladıktan veya LAST_INSERT_ID (ifade) ile bir sütun değeri ayarlamak için INSERT veya UPDATE kullandıktan sonra bu işlevi kullanın.

LAST_INSERT_ID () ve mysql_insert_id () arasındaki farkın nedeni, LAST_INSERT_ID () 'nin komut dosyalarında kullanımı kolay hale getirilirken, mysql_insert_id () AUTO_INCREMENT sütununa ne olduğu hakkında daha kesin bilgi sağlamaya çalışmasıdır.

PHP mysqli_insert_id()

LAST_INSERT_ID () işlevini kullanarak bir INSERT veya UPDATE deyimi gerçekleştirmek, mysqli_insert_id () işlevi tarafından döndürülen değeri de değiştirecektir.

Hepsini bir araya koy:

$affected_rows = DB::getAffectedRows("
    update users set status = 'processing' 
    where status = 'pending' and last_insert_id(user_id) 
    limit 1"
);
if ($affected_rows) {
    $user_id = DB::getInsertId();
}

(Bilginize, DB sınıfı burada .)


Unutulmaması gereken önemli: Bu çoklu bağlantı güvenlidir, last_insert_id veya mysql_insert_id için kalıcı değer (ve belki mysqli_insert_id, kontrol etmedim), bağlantı başına. Müthiş!
Ryan S

11

Bu, Salman A'nın cevabı ile aynı yöntemdir, ancak işte bunu yapmanız gereken kod.

İlk olarak, tablonuzu bir satır değiştirildiğinde otomatik olarak takip edecek şekilde düzenleyin. Yalnızca bir satırın başlangıçta ne zaman eklendiğini bilmek istiyorsanız son satırı kaldırın.

ALTER TABLE mytable
ADD lastmodified TIMESTAMP 
    DEFAULT CURRENT_TIMESTAMP 
    ON UPDATE CURRENT_TIMESTAMP;

Ardından, son güncellenen satırı bulmak için bu kodu kullanabilirsiniz.

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

Bu kodun tamamı MySQL vs PostgreSQL'den kaldırılmıştır : Bir Tabloya 'Last Modified Time' Sütunu Ekleme ve MySQL Kılavuzu: Satırları Sıralama . Ben sadece monte ettim.


7
İkinci ekleme, ilk ekleme sorgusundan hemen sonra yapılırsa, bu yöntem yanlış kimliği getirebilir. Ancak bu sorgu ile 'WHERE' kullanırsak, örn. Son değiştirilen DESC LIMIT 1 WHERE TARAFINDAN SEÇİMİ SEÇİM SİPARİŞİ (son ekleme sorgusuyla ilgili bazı koşullar), bu durumda yanlış kimliğin alınmasını engelleyebilir.
Naeem Ul Wahhab

1
@ TheNoble-Coder Bu doğrudur. Belirli bir güncelleme sorgusunda etkilenen satırın kimliğini almanız gerekiyorsa, Pomyk tekniğini kullanın. Buradaki bu teknik, mutlak son güncellemeyi istediğinizde eşzamansız olarak kullanıldığında daha kullanışlıdır.
Chad von Nau

5

Sorgu :

$sqlQuery = "UPDATE 
            update_table 
        SET 
            set_name = 'value' 
        WHERE 
            where_name = 'name'
        LIMIT 1;";

PHP işlevi:

function updateAndGetId($sqlQuery)
{
    mysql_query(str_replace("SET", "SET id = LAST_INSERT_ID(id),", $sqlQuery));
    return mysql_insert_id();
}

Benim için çalışıyor;)


aynısını beğendim ama farklı koştum ref: forums.mysql.com/read.php?52,390616,390619

3

Yukarıdakilere Daha Fazla Yanıt Kabul Edilmiş Cevap
Merak edenler için :=&=

Belirgin fark arasındaki :=ve =, ve bu yani :=ederken, her yerde değişken atama operatörü olarak çalışmalar =sadece SET tablolara bu şekilde çalışır ve her yerde bir karşılaştırma operatörüdür.

Yani SELECT @var = 1 + 1;bırakacak @vardeğişmeden ve bir dönüş boolean ederken, (1 veya 0 @ VAR şimdiki değerine bağlı olarak) SELECT @var := 1 + 1;değişecek @variçin 2 ve 2 dönüş . [Kaynak]


Hey teşekkürler. Demek istedikleri, aslında yukarıda kabul edilen cevaptan daha ilginç.
Green

2

Hey, sadece böyle bir numaraya ihtiyacım vardı - farklı bir şekilde çözdüm, belki senin için işe yarar. Bunun ölçeklenebilir bir çözüm olmadığını ve büyük veri kümeleri için çok kötü olacağını unutmayın.

Sorgunuzu iki bölüme ayırın -

önce, güncellemek istediğiniz satırların kimliklerini seçin ve bunları geçici bir tabloda saklayın.

ikinci olarak, orijinal güncellemeyi güncelleme ifadesindeki koşul olarak değiştirilerek yapın where id in temp_table.

Ve eşzamanlılığı sağlamak için, bu iki adımdan önce tabloyu kilitlemeniz ve ardından kilidi açmanız gerekir .

Yine, bu benim için çalışıyor, ile biten bir sorgu için limit 1, bu yüzden geçici bir tablo bile kullanmıyorum, bunun yerine ilkinin sonucunu saklamak için basit bir değişken select.

Her zaman sadece bir satırı güncelleyeceğimi ve kodun basit olduğunu bildiğim için bu yöntemi tercih ediyorum.


2
SET @uids := "";
UPDATE myf___ingtable
   SET id = id
   WHERE id < 5
  AND ( SELECT @uids := CONCAT_WS(',', CAST(id AS CHAR CHARACTER SET utf8), @uids) );
SELECT @uids;

Kimliği CAST yapmak zorunda kaldım (neden bilmiyorum) ... ya da @uids içeriğini alamıyorum (bir blob idi) Btw Pomyk cevabı için çok teşekkürler!


2

Son güncellenen satırın kimliği, o satırı bulmak ve güncellemek için "updateQuery" de kullandığınız kimlik ile aynıdır. Bu yüzden, istediğiniz şekilde bu kimliği kaydedin (arayın).

last_insert_id()bağlıdır AUTO_INCREMENT, ancak son güncellenen kimlik değil.


3
Güncelleme bir kimlikten değil de başka bir öznitelik kümesinden yapıldıysa ne olur?
Sebas

2

Benim çözümüm, önce select komutuyla "id" (@uids) 'e karar verin ve ardından bu kimliği @uids ile güncelledikten sonra.

SET @uids := (SELECT id FROM table WHERE some = 0 LIMIT 1);
UPDATE table SET col = 1 WHERE id = @uids;SELECT @uids;

projemde çalıştı.


1

Yalnızca eklemeler yapıyorsanız ve aynı oturumdan bir tane istiyorsanız, peirix'in cevabına göre yapın. Değişiklikler yapıyorsanız, en son güncellenen girişi saklamak için veritabanı şemanızı değiştirmeniz gerekecektir.

Farklı bir oturumdan (yani şu anda çalışan PHP kodu tarafından yapılan değil, farklı bir isteğe yanıt olarak yapılan) son değişiklikten gelen kimliği istiyorsanız, bir TIMESTAMP sütunu, tablonuza last_modified ( bilgi için bkz. Http://dev.mysql.com/doc/refman/5.1/en/datetime.html ) adını verin ve ardından güncellediğinizde last_modified = CURRENT_TIME olarak ayarlayın.

Bunu ayarladıktan sonra, aşağıdaki gibi bir sorgu kullanabilirsiniz: SELECT id from table ORDER BY last_modified DESC LIMIT 1; en son değiştirilen satırı almak için.


-9

Bu kadar uzun Mysql koduna gerek yok. PHP'de sorgu şunun gibi görünmelidir:

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();
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.