當使用相同的值更新 MySQL 資料表時,實際上沒有任何影響,因此 rowCount 將會返回 0。如同下方 Perl 先生所述,這並非總是預期的行為,您可以從 PHP 5.3 開始自行更改。
只需使用以下方式建立您的 PDO 物件
<? php
$p = new PDO($dsn, $u, $p, array(PDO::MYSQL_ATTR_FOUND_ROWS => true));
?>
rowCount() 就會告訴您更新查詢實際找到/符合的資料列數。
(PHP 5 >= 5.1.0, PHP 7, PHP 8, PECL pdo >= 0.1.0)
PDOStatement::rowCount — 傳回受最後一個 SQL 陳述式影響的列數
PDOStatement::rowCount() 會傳回受對應 PDOStatement
物件執行的最後一個 DELETE、INSERT 或 UPDATE 陳述式影響的列數。
對於產生結果集的陳述式,例如 SELECT
,其行為未定義,且可能因各個驅動程式而異。某些資料庫可能會傳回該陳述式產生的列數(例如緩衝模式下的 MySQL),但並非所有資料庫都保證會有此行為,因此可攜式應用程式不應依賴此行為。
注意:
這個方法在使用 SQLite 驅動程式時總是會回傳「0」(零),而使用 PostgreSQL 驅動程式時,只有在將
PDO::ATTR_CURSOR
陳述式屬性設定為PDO::CURSOR_SCROLL
時才會回傳「0」。
這個函式沒有參數。
回傳資料列的數量。
如果屬性 PDO::ATTR_ERRMODE
設定為 PDO::ERRMODE_WARNING
,則會發出層級為 E_WARNING
的錯誤。
如果屬性 PDO::ATTR_ERRMODE
設定為 PDO::ERRMODE_EXCEPTION
,則會擲出 PDOException 例外。
範例 #1 回傳已刪除資料列的數量
PDOStatement::rowCount() 會回傳受 DELETE、INSERT 或 UPDATE 陳述式影響的資料列數量。
<?php
/* 從 FRUIT 資料表刪除所有資料列 */
$del = $dbh->prepare('DELETE FROM fruit');
$del->execute();
/* 回傳已刪除的資料列數量 */
print "回傳已刪除的資料列數量:\n";
$count = $del->rowCount();
print "已刪除 $count 列資料。\n";
?>
上述範例會輸出類似以下的內容
Return number of rows that were deleted: Deleted 9 rows.
範例 #2 計算 SELECT 陳述式回傳的資料列數量
對於大多數資料庫,PDOStatement::rowCount() 不會回傳受 SELECT 陳述式影響的資料列數量。請改用 PDO::query() 發出一個與您預期的 SELECT 陳述式具有相同述詞的 SELECT COUNT(*) 陳述式,然後使用 PDOStatement::fetchColumn() 來擷取相符資料列的數量。
<?php
$sql = "SELECT COUNT(*) FROM fruit WHERE calories > 100";
$res = $conn->query($sql);
$count = $res->fetchColumn();
print "共有 " . $count . " 筆相符的記錄。";
上述範例會輸出類似以下的內容
There are 2 matching records.
當使用相同的值更新 MySQL 資料表時,實際上沒有任何影響,因此 rowCount 將會返回 0。如同下方 Perl 先生所述,這並非總是預期的行為,您可以從 PHP 5.3 開始自行更改。
只需使用以下方式建立您的 PDO 物件
<? php
$p = new PDO($dsn, $u, $p, array(PDO::MYSQL_ATTR_FOUND_ROWS => true));
?>
rowCount() 就會告訴您更新查詢實際找到/符合的資料列數。
太好了,使用 MySQL5 時,在執行 PDO SELECT 查詢後取得資料列數的唯一方法是執行另一個獨立的 SELECT COUNT(*) 查詢(或者執行 count($stmt->fetchAll()),這看起來像是對系統資源和程式設計時間的荒謬浪費)。
我對 PDO 的另一個抱怨是它無法從某些 DBMS(例如 SQL Server)的預存程序中取得輸出參數的值。
我不太確定我是否喜歡 PDO。
請注意,INSERT ... ON DUPLICATE KEY UPDATE 陳述式並非 INSERT 陳述式,rowCount 不會返回此類陳述式插入或更新的資料列數。對於 MySQL,如果插入資料列,它會返回 1,如果更新資料列,則返回 2,但这可能不適用於其他資料庫。
為了只在查詢不為空時顯示資訊,我會這樣做
<?php
$sql = 'SELECT model FROM cars';
$stmt = $db->prepare($sql);
$stmt->execute();
if ($data = $stmt->fetch()) {
do {
echo $data['model'] . '<br>';
} while ($data = $stmt->fetch());
} else {
echo '空的查詢';
}
?>
如果只使用 MySQL,最好使用 SQL_CALC_FOUND_ROWS。它有很多優點,您可以只擷取部分結果集(透過 LIMIT),但仍然可以取得總資料列數。
程式碼
<?php
$db = new PDO(DSN...);
$db->setAttribute(array(PDO::MYSQL_USE_BUFFERED_QUERY=>TRUE));
$rs = $db->query('SELECT SQL_CALC_FOUND_ROWS * FROM table LIMIT 5,15');
$rs1 = $db->query('SELECT FOUND_ROWS()');
$rowCount = (int) $rs1->fetchColumn();
?>
在某些驅動程式中,`rowCount()` 只有在使用 `prepare()` 搭配 `PDO::CURSOR_SCROLL` 時才能正常運作。
因此,您可以修改 PDO 類別:
<?php
class myPDO extends PDO
{
public function query($query, $values=null)
{
if($query == "")
return false;
if($sth = $this->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL)))
{
$res = ($values) ? $sth->execute($values) : $sth->execute();
if(!$res)
return false;
}
return $sth;
}
}
?>
現在讓我們測試一下(我使用的是 php 5.2.9-2)
<?php
函式 TestRowCount($dsn, $db_user, $db_pass)
{
$pdh = new PDO($dsn, $db_user, $db_pass);
$sth = $pdh->query("SELECT * FROM sys.tables");
顯示 "rowCount() 標準: ".$sth->rowCount()."<br>";
$pdh = new myPDO($dsn, $db_user, $db_pass);
$sth = $pdh->query("SELECT * FROM sys.tables");
顯示 "rowCount() 新方法: ".$sth->rowCount()."<br><br>";
$pdh=null;
}
$db_server = "xxx";
$db_name = "xxx";
$db_user = "xxx";
$db_pass = "xxx";
顯示 "PDO_MSSQL"."<br>";
TestRowCount("mssql:host=$db_server;dbname=$db_name", $db_user, $db_pass);
顯示 "MSSQL 透過 PDO_ODBC"."<br>";
TestRowCount("odbc:DRIVER={SQL Server};SERVER=$db_server;DATABASE=$db_name;", $db_user, $db_pass);
顯示 "MS SQL 驅動程式 2.0"."<br>";
TestRowCount("sqlsrv:server=$db_server;Database=$db_name", $db_user, $db_pass);
?>
我的結果
-------------------
PDO_MSSQL
rowCount() 標準: 0
rowCount() 新方法: 0
MSSQL 透過 PDO_ODBC
rowCount() 標準: -1
rowCount() 新方法: 53
MS SQL 驅動程式 2.0
rowCount() 標準: -1
rowCount() 新方法: 53
-------------------
使用 myPDO 類別,您可以使用準備好的查詢,例如
<?php
$pdh = new myPDO($dsn, $db_user, $db_pass);
$sth = $pdh->query("select * from data where id>? or name like ?", array(100, "A%"));
?>
注意
=====
在使用緩衝查詢的 MySQL SELECT 語句中,rowCount 會返回結果集中正確的項目數量。
但如果您的查詢是非緩衝的,則它會返回 0。無論是否已從結果集中檢取所有列(而在 mysqli 中,此行為有所不同 - 您仍然可以使用非緩衝查詢獲取結果集中的項目數量,但僅當您從集合中檢取所有列時)。
範例
========
$conn = new PDO("mysql:host=127.0.0.1;dbname=db", 'root', 'root');
// 使用非緩衝查詢
$conn->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt = $conn->query("select * from towns");
echo $stmt->rowCount(); // 總是返回 0
MySQL 似乎沒有在 rowCount 中為 select 語句返回任何內容,但您可以輕鬆有效地獲取列數,如下所示
class db extends PDO {
public function last_row_count() {
return $this->query("SELECT FOUND_ROWS()")->fetchColumn();
}
}
$myDb = new db('mysql:host=myhost;dbname=mydb', 'login', 'password' );
然後,在執行查詢後
if ( $myDb->last_row_count() == 0 ) {
echo "做一些事情!";
}
每一項好的工作
如果您使用「INSERT INTO ... ON DUPLICATE KEY UPDATE」語法,如果執行 UPDATE,mysql_affected_rows() 將返回 2(就像使用「REPLACE INTO」語法一樣),如果執行 INSERT,則返回 1。
因此,如果您使用一個 SQL 請求一次插入多行,並且有些被插入,有些只是被更新,您將無法獲得真實的計數。
嗯,我不建議查詢兩次資料庫來獲取計數,然後再獲取我想要的數據。查詢一次並同時檢索記錄計數和數據本身會更簡單,並且效能更好
<?php
$sql = "SELECT * FROM fruit WHERE calories > :calories";
$sth = $conn->prepare($sql);
$sth->bindParam(':calories', 100, PDO::PARAM_INT);
$res = $sth->execute();
if ($res) {
$record = $sth->fetchAll();
/* 檢查符合 SELECT 陳述式列數 */
if (count($record) > 0) {
foreach ($record as $row) {
print "名稱: " . $row['NAME'] . "\n";
}
}
/* 沒有符合的列 -- 執行其他操作 */
else {
print "沒有符合查詢的列。";
}
}
$conn = null;
?>
請注意 PostgreSQL 的另一個有趣行為。
如果您嘗試在使用 PDO::ATTR_CURSOR 設定為 PDO::CURSOR_SCROLL 的情況下準備陳述式後使用 rowCount(),您將始終得到零 (0)。
這是因為 PG 無法得知游標中有多少列,直到它迭代完所有列。
<?php
$st = $pdo->prepare('SELECT NOW();', [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
$st->execute();
var_dump($st->rowCount());
?>
將返回「0」,而沒有 CURSOR_SCROLL 屬性的相同陳述式將正確返回 1。
有關詳細資訊,請參閱此錯誤報告 https://bugs.php.net/bug.php?id=77855。
此文件應很快更新以反映該問題。
從 SQLite 3.x 開始,SQLite API 本身發生了變化,現在所有查詢都使用「陳述式」來實現。因此,PDO 無法得知 SELECT 結果的 rowCount,因為 SQLite API 本身不提供此功能。
作為一種解決方法,我建立了自己的 rowCount() 函數 - 這有點像是一種 hack,尚未經過完整測試(我不知道在 SELECT 中使用 JOIN 時它會如何運作等等),但至少減輕了在程式碼中到處使用 SELECT COUNT(*) 的必要性。
我比較希望可以覆寫 PDOStatement 的 rowCount() 函式,但我想這應該是不可能的(或者我不知道該怎麼做)。另外,為了安全性起見,最好在執行其他 query() 之後,將 $queryString 清空,以避免產生錯誤的結果等等……
實際的程式碼應該會貼在上面/下面的文章中(最大文章篇幅限制,唉!)。如果其他人想要擴充/完善這個方法,請透過電子郵件讓我知道你們做了哪些修改。
我們在使用 PDOStatement::fetchColumn() 和 PDOStatement::rowCount() 時遇到問題。我不確定其他人是否也遇到類似的情況,或者這只是我們程式碼的問題。在本地端,rowCount() 無法取得正確的資料列數,但在上傳到我們的虛擬主機後卻正常運作;而 fetchColumn() 則相反,在本地端正常運作,但上傳後就不行了。我不知道實際上發生了什麼事,但我認為 rowCount() 是最好的方法,其他方法則是可選的。