PHP Conference Japan 2024

PDO::lastInsertId

(PHP 5 >= 5.1.0, PHP 7, PHP 8, PECL pdo >= 0.1.0)

PDO::lastInsertId 傳回最後插入列的 ID 或序列值

說明

public PDO::lastInsertId(?string $name = null): string|false

根據底層驅動程式,返回最後插入列的 ID 或序列物件的最後一個值。例如,PDO_PGSQL 允許為 name 參數指定任何序列物件的名稱。

注意事項:

此方法在不同的 PDO 驅動程式中可能不會返回有意義或一致的結果,因為底層資料庫可能根本不支援自動遞增欄位或序列的概念。

參數

name

應從中返回 ID 的序列物件的名稱。

返回值

如果沒有為 name 參數指定序列名稱,PDO::lastInsertId() 會返回一個字串,表示最後插入到資料庫中的列的列 ID。

如果為 name 參數指定了序列名稱,PDO::lastInsertId() 會返回一個字串,表示從指定的序列物件中擷取的最後一個值。

如果 PDO 驅動程式不支援此功能,PDO::lastInsertId() 會觸發 IM001 SQLSTATE。

錯誤/例外

如果屬性 E_WARNING 設定為 PDO::ERRMODE_WARNING,則會發出級別為 E_WARNING 的錯誤。

如果屬性 PDO::ATTR_ERRMODE 設定為 PDO::ERRMODE_EXCEPTION,則會擲出 PDOException

新增註釋

使用者貢獻的註釋 12 則註釋

spark at limao dot com dot br
12 年前
請記住,如果您使用交易,則應在提交**之前**使用 lastInsertId
否則它會返回 0
toinenkayt (ta at ta) [iwonderr] gmail d
6 年前
為了節省您的一些時間。

在使用 MySQL 或 MariaDB 時,若在單個查詢中插入多列(INSERT INTO table (a,b,c) VALUES (1,2,3), (2,3,4), ...)到具有 auto_increment 欄位的表格中,PDO::lastInsertId 並**不會**返回最後一列的自動產生 ID。相反地,它會返回**第一個**產生的 ID。檢視 MySQL 和 MariaDB 的文件可以很好地解釋這一點。

從各自的文件中引用:

MySQL
「不帶參數時,LAST_INSERT_ID() 會返回一個 BIGINT UNSIGNED(64 位元)值,表示由於最近執行的 INSERT 陳述式而成功插入 AUTO_INCREMENT 欄位的第一個自動產生的值。」

MariaDB
「LAST_INSERT_ID()(不帶參數)會返回由於最近執行的 INSERT 陳述式而成功插入 AUTO_INCREMENT 欄位的第一個自動產生的值。」

這顯然與 lastInsertId 自身的文件所述不同。希望這可以避免有人除錯 ID 不符的原因。

簡而言之:(MySQL | Mariadb) + 多列插入 + PDO::lastInsertId = 第一個自動產生的 ID

在 Windows 7 上執行的 MariaDB 10.2.6 32 位元、PHP 5.6.31 32 位元和 mysqlnd 5.0.11 測試的行為。
Nour
16 年前
在 MySQL 的交易中使用 lastInsertId() 時要小心。以下程式碼會回傳 0 而不是插入的 ID。

<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');

$stmt = $dbh->prepare("INSERT INTO test (name, email) VALUES(?,?)");

try {
$dbh->beginTransaction();
$stmt->execute( array('user', 'user@example.com'));
$dbh->commit();
print
$dbh->lastInsertId();
} catch(
PDOException $e) {
$dbh->rollback();
print
"錯誤!: " . $e->getMessage() . "</br>";
}
} catch(
PDOException $e ) {
print
"錯誤!: " . $e->getMessage() . "</br>";
}
?>

當沒有例外被拋出時,lastInsertId 會回傳 0。然而,如果在呼叫 commit 之前呼叫 lastInsertId,則會回傳正確的 ID。
dave at dtracorp dot com
18 年前
如果有人想知道的話
像這樣

$val = 5;
$sql = "REPLACE table (column) VALUES (:val)";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':val', $val, PDO::PARAM_INT);
$stmt->execute();
$lastId = $dbh->lastInsertId();

無論記錄是被取代還是單純插入,都會回傳最後插入的 ID。

REPLACE 語法,簡單來說就是插入,或者刪除後再插入。
所以 lastInsertId() 仍然有效。

參考 https://mysql.dev.org.tw/doc/refman/5.0/en/replace.html
了解 REPLACE 的用法
warezthebeef at gmail dot com
13 年前
如果您透過 FreeTDS 從 Linux 存取 MSSQL/SQL Server 2008 R2(或更高版本),則有一種比以下列出的解決方案更簡潔的方法來獲取最後插入的 ID。

相關的 SQL 語法在此處說明

http://msdn.microsoft.com/en-us/library/ms177564.aspx

例如,對於包含兩欄(product_id、product_name)的表格,其中 product_id 是 uniqueidentifier 或類似類型,您可以執行以下操作。

<?php

// 假設 $dbh 連線控制碼已經建立

$sql = "INSERT INTO product (product_name) OUTPUT INSERTED.product_id VALUES (?)";

$sth = $dbh->prepare($sql);

$sth->execute(array('widgets'));

$temp = $sth->fetch(PDO::FETCH_ASSOC);

?>

則 $temp 將包含如下陣列

陣列
(
[product_id] => E1DA1CB0-676A-4CD9-A22C-90C9D4E81914
)

請注意,根據您選擇的 TDS 版本,PDO_DBLIB/FreeTDS 處理 uniqueidentifier 欄位的方式存在一些問題,這些問題直到 PHP 5.3.7 才得到修復。

關於此問題和修補程式的資訊,請參考以下連結

https://bugs.php.net/bug.php?id=54167
Yonatan Ben-Nes
17 年前
應該說明的是,此函式並不會擷取該列的 ID(主鍵),而是擷取其 OID。

因此,如果您使用的是最新版本的 PostgreSQL,除非您在建立表格時明確地新增 OID,否則此函式將無法幫助您。
ruben02 at hotmail dot com
13 年前
我想我在 Postgres 中找到了一個不錯的解決方案,可以使用 Postgres 8.2 版以來提供的 RETURNING 來取得 ID。在下面的範例中,我在 insert 子句中添加了 "returning" 以及表格的主鍵,然後在執行後,我執行 fetch 以取得包含最後插入 ID 值的陣列。

<?php
public function insert($employee){

$sqlQuery = "INSERT INTO employee(user_id,name,address,city) VALUES(:user_id,:name,:address,:city) RETURNING employee_id";

$statement = $this->prepare($sqlQuery);

$a ="2002-03-11 12:01AM" ;

$statement->bindParam(":user_id", $employee->getUserId(), PDO::PARAM_INT);
$statement->bindParam(":name", $employee->getName(), PDO::PARAM_STR);
$statement->bindParam(":address", $employee->getAddress(), PDO::PARAM_STR);
$statement->bindParam(":city", $employee->getCity(), PDO::PARAM_STR);
$statement->execute();

$result = $statement->fetch(PDO::FETCH_ASSOC);
return
$result["employee_id"];

}
?>
enclaved
7 年前
給 PostgreSQL 使用者的警告!回應 ed at hicklinslade dot com 的評論,他寫道

...
$last_insert_id = $objPDO->lastInsertId("$strTable_id_seq);

這看起來的確能如預期般運作。我不太清楚的是,這是否只是回傳序列的目前值;如果是的話,這並不是程式碼剛插入的記錄 ID 的可靠指標,尤其是在網站或應用程式的流量特別高的情況下。
...

絕對不要在 PostgreSQL 序列中使用 lastInsertId(),尤其是在應用程式的插入/更新負載量高的時候。PostgreSQL 序列是非交易性的(這是一種自然的設計特性,可以避免獨佔鎖定,否則會造成效能上的問題)。這表示任何同時增加相同序列的並行交易都會使 lastInsertId() 返回的值相對於交易的最後一次插入失效。範例:

交易 1 使用 nextval('some_seq') 插入,產生 100;
並行交易 2 使用 nextval('some_seq') 插入,產生 101;
交易 1 呼叫 lastInsertId(),預期得到 100,但卻得到 101。

對於 PostgreSQL 來說,這種 PDO 方法很笨,請務必使用 INSERT ... RETURNING 語法。
nafsinvk at gmail dot com
5 年前
$dbh->commit();
print $dbh->lastInsertId();
以上程式碼永遠會回傳零 (0)
因此在提交事務之前呼叫 $dbh->lastInsertId(); 非常重要

上述程式碼應修改為
print $dbh->lastInsertId();
$dbh->commit();
noel dot mcavoy at gmail dot com
12 年前
此函式現在與較新的 MS SQL 驅動程式相容。http://msdn.microsoft.com/en-us/library/ff628155(v=sql.105)
phpmanual at NOSPAM dot headbank dot co dot uk
2 年前
MySQL/MariaDB 使用者請注意,雖然此函式會回傳字串,但如果您的欄位具有 ZEROFILL 屬性,則開頭的零將不會被保留。
timer timer five at gmail dot com
7 年前
關於透過類別建立的連線

例如: db::SQL()->query();
然後 db::SQL()->lastInsertId();

它會建立新的連線,並且不會回傳最後插入的 ID。 最好引入一個 PDO 連線檔案(或直接使用登入資訊),並使用它來正確取得最後的 ID。

$db = new PDO(logins);
$db->query();
$db->lastInsertId();
To Top