PDO で SELECT の結果数を取得する
SELECT 文で取得した結果の数が取れなかったので調べてみたら、次のような注意書きがあった。
PDOStatement::rowCount() は 相当する PDOStatement オブジェクトによって実行された 直近の DELETE, INSERT, UPDATE 文によって作用した行数を返します。
http://php.net/manual/ja/pdostatement.rowcount.php
関連する PDOStatement によって実行された直近の SQL ステートメントが SELECT 文の場合、いくつかのデータベースは文によって返された 行数を返すかも知れません。しかしながら、 この振る舞いは全てのデータベースで保証されていません。さまざまな場所で使用するアプリケーションでは、 これに頼ってはいけません。
そして、「SELECT 文によって返された行をカウントする」ということで、
ほとんどのデータベースでは、PDOStatement::rowCount() は SELECT 文によって作用した行数を返しません。代わりに、 PDO::query() を使って 意図する SELECT 文として同様の述部を持つ SELECT COUNT(*) 文を発行し、PDOStatement::fetchColumn() を使って返される行数を取得することができます。 そうすることで、アプリケーションは正しい動作をすることができます。
http://php.net/manual/ja/pdostatement.rowcount.php
<?php $sql = "SELECT COUNT(*) FROM fruit WHERE calories > 100"; if ($res = $conn->query($sql)) { /* SELECT 文にマッチする行数をチェックする */ if ($res->fetchColumn() > 0) { /* 実際の SELECT 文を発行し、結果を処理する */ $sql = "SELECT name FROM fruit WHERE calories > 100"; foreach ($conn->query($sql) as $row) { print "Name: " . $row['NAME'] . "\n"; } } /* 行がマッチしなかった場合 -- 他に何かをする */ else { print "No rows matched the query."; } } $res = null; $conn = null; ?>
他に方法はないのか
「SELECT文で rowCount() が使えるか?」で下記のコードをサンプルが提示されている。
<?php // DB_CONNECT_STR 定数には、それぞれのDBで必要な接続情報が定義されているとして読んで下さい。 try { $db = new PDO(DB_CONNECT_STR); $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); //←この行追加 $stmt = $db->query('SELECT * FROM hoge_table '); var_dump($stmt->rowCount()); } catch (PDOException $e){ die($e->getMessage()); } ?>
上記のコードでは、PDO::prepare を利用しているが、PDO::prepare でも取得結果数を取得できる。
ただし、
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY (integer)
http://php.net/manual/ja/ref.pdo-mysql.php
PDOStatement でこの属性を TRUE に設定すると、 MySQL ドライバはバッファ版の MySQL API を使用します。 移植性の高いコードを書くには、代わりに PDOStatement::fetchAll() を使用すべきです。
とあるので、こう書くべきだろう。
<?php $id = 1; try { $db = new PDO(DB_CONNECT_STR); $sth->prepare('SELECT `id` FROM `hoge_table` WHERE `id` = :id'); $sth->bindParam(':id', $id, PDO::PARAM_INT); $sth->execute(); } catch (PDOException $e){ die($e->getMessage()); } $resultSet = $sth->fetchAll(); $resultNum = count($resultSet); if (0 < $resultNum) { do_something(); } else { ... } ?>