PDOStatement::rowCount

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

PDOStatement::rowCount返回受上次 SQL 语句影响的行数

描述

public PDOStatement::rowCount(): int

PDOStatement::rowCount() 返回由对应 PDOStatement 对象执行的最后一个 DELETE、INSERT 或 UPDATE 语句所影响的行数。

对于生成结果集的语句(例如 SELECT),行为是未定义的,并且每个驱动程序可能有所不同。一些数据库可能会返回由该语句生成的行数(例如缓冲模式下的 MySQL),但这种行为并非所有数据库都保证,不应该依赖于可移植的应用程序。

注意:

此方法在所有情况下都会使用 SQLite 驱动程序返回“0”(零),并且仅在将PDO::ATTR_CURSOR 语句属性设置为PDO::CURSOR_SCROLL 时才会使用 PostgreSQL 驱动程序返回“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.

参见

添加备注

用户贡献的备注 15 个备注

89
Ome Ko
13 年前
使用相同的更新值更新 MySQL 表时,实际上没有任何影响,因此 rowCount 将返回 0。正如 Perl 先生在下面提到的,这并不总是首选行为,您可以从 PHP 5.3 开始自行更改它。

只需使用以下方法创建您的 PDO 对象
<? php
$p = new PDO($dsn, $u, $p, array(PDO::MYSQL_ATTR_FOUND_ROWS => true));
?>
然后 rowCount() 将告诉您更新查询实际找到/匹配了多少行。
42
Matt
16 年前
太好了,在使用 MySQL5 时,执行 PDO SELECT 查询后获得行数的唯一方法是执行单独的 SELECT COUNT(*) 查询(或执行 count($stmt->fetchAll()),这似乎是一种荒谬的开销和编程时间浪费)。

我对 PDO 的另一个抱怨是,它无法在某些 DBMS(例如 SQL Server)中获取存储过程输出参数的值。

我不确定我是否还喜欢 PDO。
32
Daniel Karp
11 年前
请注意,INSERT ... ON DUPLICATE KEY UPDATE 语句不是 INSERT 语句,rowCount 不会返回为这种语句插入或更新的行数。对于 MySQL,如果插入行,它将返回 1,如果更新行,它将返回 2,但这可能不适用于其他数据库。
25
leandro at marquesini dot com
12 年前
要仅在查询不为空时显示信息,我使用以下方法

<?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
'Empty Query';
}
?>
18
gunnrosebutpeace at gmail dot com
16 年前
如果您只使用 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();
?>
13
sERGE-01
10 年前
在某些驱动程序中,rowCount() 仅在使用 prepare() 与 PDO::CURSOR_SCROLL 时才有效
因此,您可以修改 PDO 类

<?php
class myPDO extends PDO
{
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
function TestRowCount($dsn, $db_user, $db_pass)
{
$pdh = new PDO($dsn, $db_user, $db_pass);
$sth = $pdh->query("SELECT * FROM sys.tables");
print
"rowCount() Standart: ".$sth->rowCount()."<br>";

$pdh = new myPDO($dsn, $db_user, $db_pass);
$sth = $pdh->query("SELECT * FROM sys.tables");
print
"rowCount() New: ".$sth->rowCount()."<br><br>";

$pdh=null;
}

$db_server = "xxx";
$db_name = "xxx";
$db_user = "xxx";
$db_pass = "xxx";

print
"PDO_MSSQL"."<br>";
TestRowCount("mssql:host=$db_server;dbname=$db_name", $db_user, $db_pass);

print
"MSSQL throw PDO_ODBC"."<br>";
TestRowCount("odbc:DRIVER={SQL Server};SERVER=$db_server;DATABASE=$db_name;", $db_user, $db_pass);

print
"MS SQL driver 2.0"."<br>";
TestRowCount("sqlsrv:server=$db_server;Database=$db_name", $db_user, $db_pass);
?>

我的结果
-------------------
PDO_MSSQL
rowCount() Standart: 0
rowCount() New: 0

MSSQL throw PDO_ODBC
rowCount() Standart: -1
rowCount() New: 53

MS SQL driver 2.0
rowCount() Standart: -1
rowCount() New: 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%"));
?>
5
xmt at abv dot bg
6 年前
注意
=====
在 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
8
user at nospam dot example dot com
10 年前
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 "Do something!";
}
2
info at buylikesandviews dot com
9 年前
每一项好的工作
如果你使用 "INSERT INTO ... ON DUPLICATE KEY UPDATE" 语法,mysql_affected_rows() 将在更新时返回 2(就像它在 "REPLACE INTO" 语法中一样),如果插入则返回 1。

因此,如果你使用一个 SQL 请求一次插入多行,并且一些被插入,一些只是被更新,你将无法获得真实的计数。
1
lsrzj at facebook
8 年前
嗯,我不会像建议的那样查询两次数据库来获取计数,然后获取我想要的数据。查询一次并同时检索记录计数和数据本身会更简单,并且会带来更好的性能

<?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
"Name: " . $row['NAME'] . "\n";
}
}
/* 没有行匹配 - 执行其他操作 */
else {
print
"No rows matched the query.";
}
}
$conn = null;
?>
0
bohwaz
5 年前
请注意 PostgreSQL 的另一个有趣的行为。

如果你尝试在使用设置为 PDO::CURSOR_SCROLL 的 PDO::ATTR_CURSOR 准备语句后使用 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

此文档将在短期内更新以反映此问题。
-3
e dot sand at elisand dot com
15 年前
从 SQLite 3.x 开始,SQLite API 本身发生了变化,现在所有查询都是使用 "语句" 实现的。因此,PDO 无法知道 SELECT 结果的 rowCount,因为 SQLite API 本身不提供此功能。

作为一种变通方法,我创建了自己的 rowCount() 函数 - 这有点像黑客,尚未完全测试(我不知道它在 SELECT 中使用 JOIN 时会如何工作等),但至少消除了在你的代码中到处使用 SELECT COUNT(*) 的必要性。

我更希望能够从 PDOStatement 中重载 rowCount() 函数,但我认为这是不可能的(或者我不知道如何做到)。还有可能在确保 $queryString 在其他 query() 后被清除方面有更多安全措施,这样你就不会得到错误的结果等等。

实际代码应发布在上面的/下面的帖子中(帖子最大限制,啊!)。如果其他人希望扩展/完善此方法,请通过电子邮件告知我您所做的事情。
-5
@rhavendc (twitter)
8 年前
我们在使用 PDOStatement::fetchColumn() 和 PDOStatement::rowCount() 时遇到了问题。我不知道我们是否遇到与其他人相同的情况,或者这仅仅是我们代码中的问题。在本地,rowCount() 没有给出正确的行数,但在上传到我们的托管网站时它工作正常。而 fetchColumn() 则相反。fetchColumn() 在本地工作正常,但在上传后就不再工作了。我不知道究竟发生了什么,但我认为 rowCount() 是最好的,而其他方法是可选的。
-14
phpnet at maya-control dot ro
10 年前
另一个解决方法是在一个 SELECT 语句中返回行数(请参阅下面的限制!)。

$sth = $dbh->prepare("SELECT *,count(*) AS howmany FROM users WHERE email=:email and password=:pass"); #变量占位符
$sth->execute(array(':email'=>$email, ':pass'=>$pass)); #变量绑定
$row = $sth->fetch(); #获取一行(始终只有一行!!!)

if ($row['howmany'] == 1){ #匹配并只有一行!很酷!
echo $row['email'], $row['name'], $row['phone'], ... ;
} elseif ($row['howmany']>1) { #返回多行
#应该开除一个程序员,因为他没有检查
#是否存在电子邮件,然后创建新用户
...
#以某种方式处理此异常,或者直接跳过此分支,
#如果您确定您的表中不会发生这种情况
} else { #表中没有匹配项($row['howmany'] == 0)
echo "电子邮件/密码与数据库中的不匹配!";
}

优点
- 只执行一个 SELECT 语句,不需要两步!
- 它根据 WHERE 子句检查表中是否存在一行。
- 如果存在,它将返回该行的所有字段(或仅选定的字段)。

缺点
- 如果找到多行,它不会可靠地返回行字段。如果多个行响应 SELECT 查询,则查询仍然只返回一行,您不知道具体是哪一行。
也许使用 SORT BY 会使其更具可预测性(例如:“如果找到多个用户,则返回表中最后添加的用户”),但这更多是填充表初始数据的程序的良好设计的范畴。

用途
- 它非常适合检查用户/密码对是否存在于用户表中,以及如果找到用户,则返回用户的其他字段(例如姓名、电话号码等)。
-25
e dot sand at elisand dot com
15 年前
我的 rowCount() 解决方法及其用法

<?php
class MyPDO extends PDO {
private
$queryString;

public function
query(/* ... */) {
$args = func_get_args();
$this->queryString = func_get_arg(0);

return
call_user_func_array(array(&$this, 'parent::query'), $args);
}

public function
rowCount() {
$regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/i';
if (
preg_match($regex, $this->queryString, $output) > 0) {
$stmt = parent::query("SELECT COUNT(*) FROM {$output[1]}", PDO::FETCH_NUM);

return
$stmt->fetchColumn();
}

return
false;
}
}

$pdo = new MyPDO("sqlite::memory:");
$result = $pdo->query("SELECT row1, row2 FROM table WHERE something = 5");

if (
$pdo->rowCount() > 0) {
echo
"{$result['row1']}, {$result['row2']}";
}
?>
To Top