Эффективное получение количества строк, возвращаемых запросом SELECT с предложением WHERE, с использованием PDO

На SO ведутся многочисленные обсуждения того, как получить число строк, возвращенных при выполнении запроса SELECT с использованием PDO. Хотя большинство (включая руководство по PHP) предлагают использовать два запроса, причем первый запуская COUNT(), я не видел ни одного, который предлагал бы легко сделать это, используя подготовленные операторы с предложениями WHERE.

Как мне наиболее эффективно (как с точки зрения обработки, так и с точки зрения количества строк кода) запустить COUNT(), используя одно и то же предложение WHERE? В подготовленном запросе уже указаны столбцы. fetchAll() здесь не сработает, потому что это не масштабируется; если мне нужно вернуть миллионы строк, обработка их с помощью fetchAll будет очень медленной.

Например, без подсчета:

$sql = "SELECT
            FirstName,
            LastName
        FROM
            People
        WHERE
            LastName = :lastName";
$query = $pdoLink->prepare($sql);
$query->bindValue(":lastName", '%Smith%');
$query->execute();      
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
    echo $row['FirstName'] . " " . $row['LastName'];
}

Я посмотрел на простое добавление COUNT(ID) к предложению SELECT и на то, чтобы это был всего один запрос, но похоже, что нет действительно хорошего способа (или не зависящего от базы данных) способа перемотки fetch() после того, как я получаю от него строку.

Другое решение может состоять в том, чтобы сделать предложение WHERE собственной переменной, которая создается. Но это кажется не очень эффективным. Он готовит два запроса, снова связывает значения и выполняет их.

Что-то вроде:

$whereClause = " WHERE
                   LastName = :lastName";

$rowsSql = "SELECT
            COUNT(ID) As NumOfRows
        FROM
            People " . $whereClause;
$rowsQuery = $pdoLink->prepare($sql);
$rowsQuery->bindValue(":lastName", '%Smith%');
$rowsQuery->execute();
if ($rowsQuery->fetchColumn() >= 1)
    //Prepare the original query, bind it, and execute it.
    $sql = "SELECT
                FirstName,
                LastName
            FROM
                People " . $whereClause;
    $query = $pdoLink->prepare($sql);
    $query->bindValue(":lastName", '%Smith%');
    $query->execute();      
    while($row = $query->fetch(PDO::FETCH_ASSOC)) {
        echo $row['FirstName'] . " " . $row['LastName'];
    }
}
else
{
    //No rows found, display message
    echo "No people found with that name.";
}

person Luke Shaheen    schedule 08.04.2013    source источник
comment
возможный дубликат Альтернатива для mysql_num_rows с использованием PDO   -  person Marc B    schedule 08.04.2013
comment
@MarcB Как я указал в начале своего вопроса, я не нашел примера, в котором используется предложение WHERE. Мой вопрос касается того, как эффективно это сделать, используя предложение WHERE.   -  person Luke Shaheen    schedule 08.04.2013
comment
вы хотите количество строк, сгруппированных по фамилии?   -  person Miguelo    schedule 08.04.2013
comment
@Miguelo Это вымышленный пример - я хочу, чтобы количество строк возвращалось моим оператором SELECT с использованием предложения WHERE. То, что находится в пункте WHERE, не должно иметь значения.   -  person Luke Shaheen    schedule 09.04.2013
comment
хорошо, но на основе вашего примера вы хотите использовать группу по   -  person Miguelo    schedule 09.04.2013
comment
@Miguelo Как использование GROUP BY позволит моему PHP-коду узнать, возвращаются ли строки или нет? Смысл здесь в том, чтобы отобразить сообщение, если строки не найдены, иначе напечатать строки.   -  person Luke Shaheen    schedule 09.04.2013
comment
объедините его с предложением HAVING, чтобы он не возвращал строк, где счетчик равен 0   -  person Miguelo    schedule 09.04.2013
comment
@Miguelo Спасибо, но это не позволит моему PHP определить, возвращаются строки или нет.   -  person Luke Shaheen    schedule 09.04.2013
comment
Метод fetchAll должен подойти для вашего примера, потому что ваш результирующий набор не содержит много строк. Вы можете использовать PHP count для подсчета строк.   -  person bitWorking    schedule 09.04.2013
comment
@redreggae Это не очень хорошее решение, потому что моя таблица «Люди» (или другая таблица, с которой я ее использую) может иметь миллионы строк, и использование fetchAll в этих случаях было бы очень неэффективным.   -  person Luke Shaheen    schedule 09.04.2013
comment
@Shikiryu В этом вопросе используется SQLite, я спрашиваю о MySQL. На этот вопрос нет принятого ответа, а ответ, набравший наибольшее количество голосов, не показывает наиболее эффективный способ выполнения обоих запросов; он просто показывает выполнение запроса COUNT().   -  person Luke Shaheen    schedule 09.04.2013


Ответы (2)


При использовании MySQL PDOStatement::rowCount() возвращает количество строк в результирующем наборе. На самом деле он вызывает базовую функцию mysql_num_rows() C для заполнения ценность. Нет необходимости в нескольких запросах или любой другой возне.

Это верно для MySQL, но на это поведение нельзя полагаться для других драйверов (другие могут поддерживать его, но это не гарантируется, я недостаточно знаком с другими, чтобы сказать наверняка в любом случае). Но поскольку ваш вопрос касается конкретно MySQL, он должен служить вашим целям.

person DaveRandom    schedule 08.04.2013
comment
Отлично, спасибо за ссылку на базовый код. Кажется, существует много неправильных представлений о том, какие драйверы правильно используют rowCount()! - person Luke Shaheen; 09.04.2013
comment
Какие? Место, где документация по PHP неадекватно описывает нюансы языка? Я не верю. Я не поверю в это. :-П - person DaveRandom; 09.04.2013

Попробуйте эту встроенную функцию PDO; $запрос->rowCount();

person patrick nwakwoke    schedule 14.09.2017