Làm cách nào để lấy ID của hàng cập nhật cuối cùng trong MySQL?


134

Làm cách nào để có được ID của hàng được cập nhật cuối cùng trong MySQL bằng PHP?


2
mysqli_insert_id ($ link) sẽ trả về chính xác id của hàng được cập nhật mới nhất. Tôi đang sử dụng chức năng này trong các dự án của tôi cho cùng một mục đích. Bạn có thể sử dụng cả hai trong các truy vấn đồng bộ hoặc không đồng bộ. Chỉ cần chèn $ lastupdated_row_id = mysqli_insert_id ($ link) vào mã của bạn và nó sẽ hoạt động cho bạn.
Naeem Ul Wahhab

1
Bạn chưa biết ID của hàng nếu bạn cập nhật? Tôi đoán phải có một số trường hợp bạn không.
JCharette

1
Bạn có thể sử dụng mệnh đề where trong truy vấn cập nhật của mình, tại sao bạn không thể sử dụng mệnh đề where tương tự trong truy vấn chọn? UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1?
Salman A

Câu trả lời:


236

Tôi đã tìm thấy câu trả lời cho vấn đề này :)

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;

EDIT bởi aefxx

Kỹ thuật này có thể được mở rộng hơn nữa để lấy ID của mỗi hàng bị ảnh hưởng bởi câu lệnh cập nhật:

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

Điều này sẽ trả về một chuỗi với tất cả các ID được nối bằng dấu phẩy.


6
Không thể tin rằng điều này có 0 lượt upvote và nhận xét mysql_insert_id () không phải là điều OP đã hỏi tất cả có 13. Cảm ơn Pomyk, một mẹo thông minh!
Jaka Jančar

1
Vì bạn có một WHEREmệnh đề, bạn chỉ cần sử dụng cùng một WHEREmệnh đề trong truy vấn tiếp theo của mìnhSELECT id FROM footable WHERE fooid > 5
Salman A

4
Có thể mọi người đều hiểu điều này, nhưng nếu bạn sử dụng mysql_query (); bạn phải chia nó thành ba cuộc gọi khác nhau, nhưng nó sẽ hoạt động.
rael_kid

8
Thậm chí không cần sử dụng biến. LAST_INSERT_ID()có thể chấp nhận một đối số sẽ đặt giá trị được trả về bởi cuộc gọi tiếp theo LAST_INSERT_ID(). Ví dụ : UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';. Bây giờ, SELECT LAST_INSERT_ID();sẽ trả về id cập nhật. Xem câu trả lời của newtover để biết thêm chi tiết.
Joel

3
@SteveChilds Tôi chỉ bình luận câu hỏi của newtover và muốn thêm một giải pháp cho cạm bẫy mà bạn mô tả. Điều này đặt LAST_INSERT_ID thành 0 nếu không có gì để CẬP NHẬT : UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);. Tuy nhiên, nó không lấy được nhiều id, vì vậy câu trả lời này là vượt trội.
martinczerwi

33

Hừm, tôi ngạc nhiên rằng trong số những câu trả lời tôi không thấy giải pháp đơn giản nhất.

Giả sử, item_idlà một cột nhận dạng số nguyên trong itemsbảng và bạn cập nhật các hàng bằng câu lệnh sau:

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

Sau đó, để biết hàng bị ảnh hưởng mới nhất ngay sau câu lệnh, bạn nên cập nhật một chút về câu lệnh sau:

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

Nếu bạn chỉ cần cập nhật hàng thực sự thay đổi, bạn sẽ cần thêm bản cập nhật có điều kiện của item_id thông qua kiểm tra LAST_INSERT_ID nếu dữ liệu sẽ thay đổi trong hàng.


3
Nó an toàn cho nhiều người dùng vì nhiều khách hàng có thể đưa ra câu lệnh CẬP NHẬT và nhận giá trị chuỗi riêng của họ bằng câu lệnh SELECT (hoặc mysql_insert_id ()), mà không ảnh hưởng hoặc bị ảnh hưởng bởi các máy khách khác tạo ra giá trị chuỗi riêng của họ. Theo dev.mysql.com/doc/refman/5.0/en/ Từ
brutuscat

1
Điều này có đặt item_id thành bản ghi được chèn cuối cùng không?
arleslie

2
@arleslie, nếu bạn theo liên kết đến các tài liệu trong bình luận của brutuscat ở trên, bạn sẽ thấy nó sẽ không. Đây là hành vi dự định chính xác cho trường hợp.
newtover

1
Đây thực sự là câu trả lời chính xác. Mặc dù truy vấn có vẻ hơi trực quan, nhưng đây chính xác là những gì Tài liệu MySQL nói để làm.
Timothy Zorn

3
Trong trường hợp truy vấn làm bạn bối rối, vì LAST_INSERT_ID (expr) sẽ trả về giá trị của expr cho cuộc gọi CẬP NHẬT, bạn cũng có thể sử dụng nó như sau:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
martinczerwi

14

Đây là chính thức đơn giản nhưng đáng chú ý phản trực giác. Nếu bạn đang làm:

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

Thay đổi nó thành này:

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

Việc thêm last_insert_id(user_id)vào trong wheremệnh đề là yêu cầu MySQL đặt biến nội bộ của nó thành ID của hàng tìm thấy. Khi bạn chuyển một giá trị cholast_insert_id(expr) như thế này, cuối cùng nó sẽ trả về giá trị đó, trong trường hợp ID như ở đây luôn là một số nguyên dương và do đó luôn luôn đánh giá là đúng, không bao giờ can thiệp vào mệnh đề where. Điều này chỉ hoạt động nếu một số hàng thực sự được tìm thấy, vì vậy hãy nhớ kiểm tra các hàng bị ảnh hưởng. Sau đó, bạn có thể nhận được ID theo nhiều cách.

MySQL last_insert_id()

Bạn có thể tạo các chuỗi mà không cần gọi LAST_INSERT_ID (), nhưng tiện ích của việc sử dụng hàm theo cách này là giá trị ID được duy trì trong máy chủ làm giá trị được tạo tự động cuối cùng. Nó an toàn cho nhiều người dùng vì nhiều khách hàng có thể đưa ra câu lệnh CẬP NHẬT và nhận giá trị chuỗi riêng của họ bằng câu lệnh SELECT (hoặc mysql_insert_id ()), mà không ảnh hưởng hoặc bị ảnh hưởng bởi các máy khách khác tạo ra giá trị chuỗi riêng của họ.

MySQL mysql_insert_id()

Trả về giá trị được tạo cho cột AUTO_INCREMENT bằng câu lệnh INSERT hoặc UPDATE trước đó. Sử dụng chức năng này sau khi bạn đã thực hiện một câu lệnh INSERT vào một bảng có chứa trường AUTO_INCREMENT hoặc đã sử dụng INSERT hoặc UPDATE để đặt giá trị cột với LAST_INSERT_ID (expr).

Lý do cho sự khác biệt giữa LAST_INSERT_ID () và mysql_insert_id () là LAST_INSERT_ID () được sử dụng dễ dàng trong các tập lệnh trong khi mysql_insert_id () cố gắng cung cấp thông tin chính xác hơn về những gì xảy ra với cột AUTO_INCREMENT.

PHP mysqli_insert_id()

Thực hiện câu lệnh INSERT hoặc UPDATE bằng hàm LAST_INSERT_ID () cũng sẽ sửa đổi giá trị được trả về bởi hàm mysqli_insert_id ().

Để tất cả chúng cùng nhau:

$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 rằng lớp DB ở đây .)


Điều quan trọng cần lưu ý: đây là an toàn đa kết nối, giá trị bền vững cho last_insert_id hoặc mysql_insert_id (và có thể mysqli_insert_id, tôi không kiểm tra), là mỗi kết nối. Tuyệt vời!
Ryan S

10

Đây là phương pháp tương tự như câu trả lời của Salman A, nhưng đây là mã bạn thực sự cần để làm điều đó.

Đầu tiên, chỉnh sửa bảng của bạn để nó sẽ tự động theo dõi bất cứ khi nào một hàng được sửa đổi. Xóa dòng cuối cùng nếu bạn chỉ muốn biết khi nào một hàng ban đầu được chèn.

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

Sau đó, để tìm ra hàng cập nhật cuối cùng, bạn có thể sử dụng mã này.

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

Tất cả mã này được nâng lên từ MySQL so với PostgreSQL: Thêm cột 'Thời gian sửa đổi lần cuối' vào BảngHướng dẫn sử dụng MySQL: Sắp xếp hàng . Tôi chỉ lắp ráp nó.


7
Phương pháp này có thể tìm nạp id sai nếu lần chèn thứ hai được thực hiện ngay sau truy vấn chèn đầu tiên. Tuy nhiên Nếu chúng tôi sử dụng 'WHERE' với truy vấn này, ví dụ: CHỌN id TỪ LỆNH mytable B BYNG LỆNH GIỚI HẠN MÔ TẢ 1 WHERE (một số điều kiện liên quan đến truy vấn chèn cuối cùng), thì nó có thể ngăn không tải được id sai.
Naeem Ul Wahhab

1
@ TheNoble-Coder Điều này đúng. Nếu bạn cần lấy id của một hàng ảnh hưởng đến một truy vấn cập nhật cụ thể, thì hãy sử dụng kỹ thuật của Pomyk. Kỹ thuật này ở đây hữu ích hơn khi được sử dụng không đồng bộ, nơi bạn chỉ muốn cập nhật cuối cùng tuyệt đối.
Chad von Nau

5

Truy vấn :

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

Hàm PHP:

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

Nó làm việc cho tôi;)


tôi thích tương tự nhưng chạy differntly ref: forums.mysql.com/read.php?52,390616,390619

3

Hơn nữa với câu trả lời được chấp nhận ở trên
Đối với những người thắc mắc về :=&=

Sự khác biệt đáng kể giữa :==, và đó là :=hoạt động như một toán tử gán biến ở mọi nơi, trong khi =chỉ hoạt động theo cách đó trong các câu lệnh SET và là toán tử so sánh ở mọi nơi khác.

Vì vậy, SELECT @var = 1 + 1;sẽ @varkhông thay đổi và trả về một boolean (1 hoặc 0 tùy thuộc vào giá trị hiện tại của @var), trong khi SELECT @var := 1 + 1;sẽ thay đổi @varthành 2trả về 2 . [Nguồn]


Này cảm ơn nhé. Những gì họ có nghĩa là thực sự thú vị hơn câu trả lời được chấp nhận ở trên.
Xanh

2

Này, tôi chỉ cần một mẹo như vậy - tôi đã giải quyết nó theo một cách khác, có thể nó sẽ hiệu quả với bạn. Lưu ý đây không phải là một giải pháp có thể mở rộng và sẽ rất tệ cho các tập dữ liệu lớn.

Chia truy vấn của bạn thành hai phần -

đầu tiên, chọn id của các hàng bạn muốn cập nhật và lưu trữ chúng trong một bảng tạm thời.

Thứ hai, thực hiện cập nhật ban đầu với điều kiện trong câu lệnh cập nhật được đổi thành where id in temp_table.

Và để đảm bảo đồng thời, bạn cần khóa bảng trước hai bước này và sau đó nhả khóa ở cuối.

Một lần nữa, điều này làm việc với tôi, đối với một truy vấn kết thúc bằng limit 1, vì vậy tôi thậm chí không sử dụng bảng tạm thời, mà thay vào đó chỉ đơn giản là một biến để lưu trữ kết quả của lần đầu tiên select.

Tôi thích phương pháp này vì tôi biết tôi sẽ luôn cập nhật chỉ một hàng và mã rất đơn giản.


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;

Tôi đã phải CAST id (dunno why) ... hoặc tôi không thể có được nội dung @uids (đó là một blob) Btw cảm ơn rất nhiều vì câu trả lời của Pomyk!


2

ID của hàng được cập nhật gần nhất là cùng một ID mà bạn sử dụng trong 'updateQuery' để tìm và cập nhật hàng đó. Vì vậy, chỉ cần lưu (gọi) ID đó vào bất cứ cách nào bạn muốn.

last_insert_id()phụ thuộc vào AUTO_INCREMENT, nhưng ID cập nhật cuối cùng thì không.


3
Điều gì xảy ra nếu việc cập nhật không được thực hiện từ một id mà là một tập các thuộc tính khác?
Sabas

2

Giải pháp của tôi là, trước tiên hãy quyết định "id" (@uids) bằng lệnh select và sau khi cập nhật id này với @uids.

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

nó đã làm việc trong dự án của tôi.


1

Nếu bạn chỉ thực hiện chèn thêm và muốn một từ cùng một phiên, hãy thực hiện theo câu trả lời của peirix. Nếu bạn đang thực hiện sửa đổi, bạn sẽ cần sửa đổi lược đồ cơ sở dữ liệu của mình để lưu trữ mục nhập nào được cập nhật gần đây nhất.

Nếu bạn muốn id từ lần sửa đổi cuối cùng, có thể là từ một phiên khác (nghĩa là không phải là phiên bản vừa được thực hiện bởi mã PHP đang chạy, nhưng một lần thực hiện theo yêu cầu khác), bạn có thể thêm một yêu cầu khác Cột TIMESTAMP vào bảng của bạn được gọi là last_modified (xem http://dev.mysql.com/doc/refman/5.1/en/datetime.html để biết thông tin), sau đó khi bạn cập nhật, hãy đặt last_modified = CURRENT_TIME.

Sau khi thiết lập điều này, sau đó bạn có thể sử dụng một truy vấn như: CHỌN id TỪ bảng ĐẶT HÀNG B lastNG Last_modified DESC LIMIT 1; để có được hàng sửa đổi gần đây nhất.


-9

Không cần mã Mysql quá dài. Trong PHP, truy vấn sẽ trông giống như thế này:

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.