จะรับ ID ของแถวที่อัปเดตล่าสุดใน MySQL ได้อย่างไร


138

ฉันจะรับ ID ของแถวที่อัปเดตล่าสุดใน MySQL โดยใช้ PHP ได้อย่างไร


2
mysqli_insert_id ($ link) จะส่งคืน id ของแถวที่อัปเดตล่าสุด ฉันใช้ฟังก์ชั่นนี้ในโครงการของฉันเพื่อจุดประสงค์เดียวกัน คุณสามารถใช้ได้ทั้งในแบบสอบถามแบบซิงโครนัสหรืออะซิงโครนัส เพียงแค่ใส่ $ lastupdated_row_id = mysqli_insert_id ($ link) ลงในโค้ดของคุณและมันจะทำงานให้คุณ
Naeem Ul Wahhab

1
คุณไม่ทราบ ID ของแถวถ้าคุณอัปเดต? ฉันเดาว่าต้องมีบางกรณีที่คุณไม่ทำ
jlcharette

1
คุณอาจใช้คำสั่ง where ในแบบสอบถามการอัปเดตของคุณเหตุใดคุณจึงไม่สามารถใช้คำสั่งเดียวกับที่คำสั่งในแบบสอบถามเลือกได้ UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1เหรอ?
Salman A

คำตอบ:


242

ฉันพบคำตอบสำหรับปัญหานี้แล้ว :)

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;

แก้ไขโดย aefxx

เทคนิคนี้สามารถขยายเพิ่มเติมเพื่อดึง ID ของทุกแถวที่ได้รับผลกระทบจากคำสั่งอัพเดต:

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

สิ่งนี้จะส่งคืนสตริงที่มี ID ทั้งหมดเชื่อมต่อกันด้วยลูกน้ำ


7
ไม่อยากจะเชื่อเลยว่าสิ่งนี้มี 0 upvotes และ mysql_insert_id () ความคิดเห็นซึ่งไม่ใช่สิ่งที่ OP ขอเลยมี 13 ขอบคุณ Pomyk เคล็ดลับที่ชาญฉลาด!
Jaka Jančar

1
เนื่องจากคุณมีWHEREอนุประโยคคุณสามารถใช้WHEREประโยคเดียวกันในการสืบค้นถัดไปของคุณได้SELECT id FROM footable WHERE fooid > 5
Salman A

4
บางทีทุกคนอาจเข้าใจสิ่งนี้ แต่ถ้าคุณใช้ mysql_query (); คุณต้องแบ่งสิ่งนี้ออกเป็นสามสายที่แตกต่างกัน แต่จะได้ผล
rael_kid

8
ไม่จำเป็นต้องใช้ตัวแปร สามารถยอมรับข้อโต้แย้งที่จะตั้งค่าส่งกลับโดยโทรไปไปยังLAST_INSERT_ID() LAST_INSERT_ID()ตัวอย่างเช่น: UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';. ตอนนี้SELECT LAST_INSERT_ID();จะส่งคืน id ที่อัปเดตแล้ว ดูคำตอบของ newtover สำหรับรายละเอียดเพิ่มเติม
Joel

3
@SteveChilds ฉันแค่แสดงความคิดเห็นเกี่ยวกับคำถามของ Newtover และต้องการเพิ่มวิธีแก้ไขข้อผิดพลาดที่คุณกำลังอธิบาย ชุดนี้ LAST_INSERT_ID 0 ถ้ามีอะไรที่จะ UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);UPDATE: อย่างไรก็ตามมันไม่ได้ดึงหลายรหัสดังนั้นคำตอบนี้ดีกว่า
martinczerwi

34

ฉันแปลกใจที่ในบรรดาคำตอบฉันไม่เห็นวิธีแก้ปัญหาที่ง่ายที่สุด

สมมติว่าitem_idเป็นคอลัมน์ข้อมูลประจำตัวจำนวนเต็มในitemsตารางและคุณอัปเดตแถวด้วยคำสั่งต่อไปนี้:

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

จากนั้นหากต้องการทราบแถวที่ได้รับผลกระทบล่าสุดหลังจากคำสั่งคุณควรอัปเดตข้อความต่อไปนี้เล็กน้อย:

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

หากคุณต้องการอัปเดตเฉพาะแถวที่มีการเปลี่ยนแปลงจริงๆคุณจะต้องเพิ่มการอัปเดตตามเงื่อนไขของ item_id ผ่านทาง LAST_INSERT_ID เพื่อตรวจสอบว่าข้อมูลกำลังจะเปลี่ยนแปลงในแถวหรือไม่


4
ปลอดภัยสำหรับผู้ใช้หลายคนเนื่องจากไคลเอนต์หลายตัวสามารถออกคำสั่ง UPDATE และรับค่าลำดับของตนเองด้วยคำสั่ง SELECT (หรือ mysql_insert_id ()) โดยไม่ส่งผลกระทบหรือได้รับผลกระทบจากไคลเอนต์อื่นที่สร้างค่าลำดับของตนเอง ตามdev.mysql.com/doc/refman/5.0/en/…
brutuscat

1
จะไม่ตั้งค่า item_id เป็นระเบียนที่แทรกล่าสุดใช่หรือไม่
arleslie

2
@arleslie ถ้าคุณไปตามลิงค์ไปยังเอกสารในความคิดเห็นของ brutuscat ด้านบนคุณจะไม่เห็นมัน นี่เป็นพฤติกรรมที่ตั้งใจไว้สำหรับกรณีนี้
ใหม่

2
นี่คือคำตอบที่ถูกต้อง แม้ว่าข้อความค้นหาจะดูไม่ซับซ้อน แต่นี่คือสิ่งที่เอกสาร MySQL บอกว่าจะทำ
Timothy Zorn

3
ในกรณีที่ข้อความค้นหาทำให้คุณสับสนเนื่องจาก LAST_INSERT_ID (expr) จะส่งคืนค่า expr สำหรับการโทร UPDATE คุณสามารถใช้ได้เช่นนี้:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
martinczerwi

14

นี่เป็นเรื่องง่ายอย่างเป็นทางการ แต่ใช้งานง่ายอย่างน่าทึ่ง หากคุณกำลังทำ:

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

เปลี่ยนเป็นสิ่งนี้:

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

การเพิ่มlast_insert_id(user_id)ในwhereประโยคเป็นการบอกให้ MySQL ตั้งค่าตัวแปรภายในเป็น ID ของแถวที่พบ เมื่อคุณส่งค่าไปlast_insert_id(expr)เช่นนี้มันจะส่งกลับค่านั้นซึ่งในกรณีของ ID เช่นนี้จะเป็นจำนวนเต็มบวกเสมอดังนั้นจึงประเมินค่าเป็นจริงเสมอไม่รบกวนกับประโยคที่ สิ่งนี้ใช้ได้เฉพาะเมื่อพบบางแถวเท่านั้นดังนั้นอย่าลืมตรวจสอบแถวที่ได้รับผลกระทบ จากนั้นคุณสามารถรับ ID ได้หลายวิธี

MySQL last_insert_id()

คุณสามารถสร้างลำดับได้โดยไม่ต้องเรียก LAST_INSERT_ID () แต่ยูทิลิตี้ของการใช้ฟังก์ชันด้วยวิธีนี้คือค่า ID จะถูกคงไว้ในเซิร์ฟเวอร์เป็นค่าสุดท้ายที่สร้างขึ้นโดยอัตโนมัติ ปลอดภัยสำหรับผู้ใช้หลายคนเนื่องจากไคลเอนต์หลายรายสามารถออกคำสั่ง UPDATE และรับค่าลำดับของตนเองด้วยคำสั่ง SELECT (หรือ mysql_insert_id ()) โดยไม่ส่งผลกระทบหรือได้รับผลกระทบจากไคลเอนต์อื่นที่สร้างค่าลำดับของตนเอง

MySQL mysql_insert_id()

ส่งคืนค่าที่สร้างขึ้นสำหรับคอลัมน์ AUTO_INCREMENT โดยคำสั่ง INSERT หรือ UPDATE ก่อนหน้า ใช้ฟังก์ชันนี้หลังจากที่คุณดำเนินการคำสั่ง INSERT ในตารางที่มีฟิลด์ AUTO_INCREMENT หรือใช้ INSERT หรือ UPDATE เพื่อตั้งค่าคอลัมน์ด้วย LAST_INSERT_ID (expr)

สาเหตุของความแตกต่างระหว่าง LAST_INSERT_ID () และ mysql_insert_id () คือ LAST_INSERT_ID () ใช้งานง่ายในสคริปต์ในขณะที่ mysql_insert_id () พยายามให้ข้อมูลที่แน่นอนมากขึ้นเกี่ยวกับสิ่งที่เกิดขึ้นกับคอลัมน์ AUTO_INCREMENT

PHP mysqli_insert_id()

การดำเนินการคำสั่ง INSERT หรือ UPDATE โดยใช้ฟังก์ชัน LAST_INSERT_ID () จะแก้ไขค่าที่ส่งคืนโดยฟังก์ชัน mysqli_insert_id ()

วางมันทั้งหมดเข้าด้วยกัน:

$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();
}

(FYI ที่คลาส DB อยู่ที่นี่ )


สิ่งสำคัญที่ควรทราบ: นี่คือความปลอดภัยในการเชื่อมต่อหลายจุดค่าที่คงอยู่สำหรับ last_insert_id หรือ mysql_insert_id (และอาจจะเป็น mysqli_insert_id ที่ฉันไม่ได้ตรวจสอบ) เป็นค่าต่อการเชื่อมต่อ สุดยอด!
Ryan S

11

นี่เป็นวิธีเดียวกับคำตอบของ Salman A แต่นี่คือรหัสที่คุณต้องทำจริงๆ

ขั้นแรกแก้ไขตารางของคุณเพื่อให้ติดตามโดยอัตโนมัติเมื่อใดก็ตามที่มีการแก้ไขแถว ลบบรรทัดสุดท้ายหากคุณต้องการทราบเมื่อมีการแทรกแถวครั้งแรกเท่านั้น

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

จากนั้นหากต้องการทราบแถวที่อัปเดตล่าสุดคุณสามารถใช้รหัสนี้

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

รหัสนี้คือทั้งหมดที่ยกมาจากMySQL เทียบกับ PostgreSQL: การเพิ่ม 'เวลาที่แก้ไขล่าสุด' คอลัมน์กับตารางและMySQL คู่มือการใช้งาน: การเรียงลำดับแถว ฉันเพิ่งประกอบมัน


7
วิธีนี้อาจดึงรหัสที่ไม่ถูกต้องหากการแทรกครั้งที่สองเสร็จสิ้นหลังจากแบบสอบถามแทรกแรก อย่างไรก็ตามหากเราใช้ 'WHERE' กับคำค้นหานี้เช่น SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1 WHERE (เงื่อนไขบางประการที่เกี่ยวข้องกับการค้นหาการแทรกครั้งสุดท้าย) อาจป้องกันไม่ให้ดึงรหัสที่ไม่ถูกต้อง
Naeem Ul Wahhab

1
@ TheNoble-Coder นี่คือเรื่องจริง หากคุณต้องการรับ id ของแถวที่มีผลต่อแบบสอบถามการอัปเดตเฉพาะให้ใช้เทคนิคของ Pomyk เทคนิคนี้มีประโยชน์มากขึ้นเมื่อใช้แบบอะซิงโครนัสโดยที่คุณต้องการอัปเดตล่าสุดอย่างแท้จริง
Chad von Nau

5

คำถาม:

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

ฟังก์ชัน PHP:

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

มันได้ผลสำหรับฉัน;)


ฉันชอบสิ่งเดียวกัน แต่วิ่งไม่เหมือนกัน ref: forums.mysql.com/read.php?52,390616,390619

3

เพิ่มเติมจากคำตอบที่ยอมรับข้างต้น
สำหรับผู้ที่สงสัยเกี่ยวกับ:=&=

ความแตกต่างที่สำคัญระหว่าง:=และ=และนั่นคือ:=ทำงานเป็นตัวดำเนินการกำหนดตัวแปรได้ทุกที่ในขณะที่=ทำงานในลักษณะนั้นในคำสั่ง SET เท่านั้นและเป็นตัวดำเนินการเปรียบเทียบที่อื่น

ดังนั้นSELECT @var = 1 + 1;จะออก@varไม่เปลี่ยนแปลงและกลับมาเป็นบูลีน (1 หรือ 0 ขึ้นอยู่กับมูลค่าปัจจุบันของ @var) ในขณะที่SELECT @var := 1 + 1;จะมีการเปลี่ยนแปลง@varไป2และกลับ 2 [ที่มา]


เฮ้ขอบคุณ สิ่งที่พวกเขาหมายถึงนั้นน่าสนใจมากกว่าคำตอบที่ยอมรับข้างต้น
กรีน

2

เฮ้ฉันแค่ต้องการเคล็ดลับแบบนั้น - ฉันแก้ไขด้วยวิธีอื่นบางทีมันอาจจะได้ผลสำหรับคุณ โปรดทราบว่านี่ไม่ใช่โซลูชันที่ปรับขนาดได้และจะไม่ดีสำหรับชุดข้อมูลขนาดใหญ่

แบ่งคำถามของคุณออกเป็นสองส่วน -

ขั้นแรกให้เลือกรหัสของแถวที่คุณต้องการอัปเดตและเก็บไว้ในตารางชั่วคราว

ประการที่สองทำการอัปเดตดั้งเดิมโดยมีเงื่อนไขในคำสั่งอัพเดตเปลี่ยนเป็น where id in temp_table .

และเพื่อให้แน่ใจว่าการทำงานพร้อมกันคุณต้องล็อกตารางก่อนสองขั้นตอนนี้จากนั้นจึงคลายล็อกในตอนท้าย

อีกครั้งสิ่งนี้ใช้ได้กับฉันสำหรับแบบสอบถามที่ลงท้ายด้วยlimit 1ดังนั้นฉันจึงไม่ได้ใช้ตาราง temp แต่เป็นเพียงตัวแปรเพื่อเก็บผลลัพธ์ของครั้งแรกselectแต่เพียงตัวแปรในการจัดเก็บผลมาจากครั้งแรก

ฉันชอบวิธีนี้เนื่องจากฉันรู้ว่าฉันจะอัปเดตเพียงแถวเดียวเสมอและรหัสก็ตรงไปตรงมา


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;

ฉันต้องแคสต์รหัส (ไม่รู้ทำไม) ... หรือฉันไม่สามารถรับเนื้อหา @uids (มันเป็นหยด) ขอบคุณมากสำหรับคำตอบของ Pomyk!


2

ID ของแถวที่อัปเดตล่าสุดคือ ID เดียวกับที่คุณใช้ใน 'updateQuery' เพื่อค้นหาและอัปเดตแถวนั้น ดังนั้นเพียงบันทึก (โทร) ID นั้นตามที่คุณต้องการ

last_insert_id()ขึ้นอยู่กับAUTO_INCREMENTแต่ ID ที่อัปเดตล่าสุดไม่ใช่


3
จะเกิดอะไรขึ้นถ้าการอัปเดตไม่ได้ทำจาก id แต่เป็นชุดของคุณสมบัติอื่น
Sebas

2

วิธีแก้ปัญหาของฉันคือก่อนอื่นให้เลือก "id" (@uids) ด้วยคำสั่ง select และหลังจากอัปเดต id นี้ด้วย @uids

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

มันทำงานในโครงการของฉัน


1

หากคุณทำเฉพาะส่วนแทรกและต้องการหนึ่งจากเซสชันเดียวกันให้ทำตามคำตอบของ peirix หากคุณกำลังทำการแก้ไขคุณจะต้องแก้ไขสคีมาฐานข้อมูลของคุณเพื่อจัดเก็บว่ารายการใดที่อัปเดตล่าสุด

หากคุณต้องการรหัสจากการแก้ไขครั้งล่าสุดซึ่งอาจมาจากเซสชันอื่น (เช่นไม่ใช่รหัสที่เพิ่งทำโดยโค้ด PHP ที่ทำงานอยู่ในปัจจุบัน แต่ทำเพื่อตอบสนองคำขออื่น) คุณสามารถเพิ่ม TIMESTAMP ในตารางของคุณที่เรียกว่า last_modified (ดูข้อมูลที่http://dev.mysql.com/doc/refman/5.1/th/datetime.html ) จากนั้นเมื่อคุณอัปเดตให้ตั้งค่า last_modified = CURRENT_TIME

เมื่อตั้งค่านี้แล้วคุณสามารถใช้แบบสอบถามเช่น: SELECT id FROM table ORDER BY last_modified DESC LIMIT 1; เพื่อรับแถวที่แก้ไขล่าสุด


-9

ไม่จำเป็นต้องใช้รหัส Mysql ที่ยาวมาก ใน PHP แบบสอบถามควรมีลักษณะดังนี้:

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.