Возможно ли перемотать результат PDO?

Я пытаюсь написать итератор для результатов из инструкции PDO, но я не могу найти способ перемотки в первую строку. Я хотел бы избежать накладных расходов на вызов fetchAll и сохранение всех данных результата.

// first loop works fine
foreach($statement as $result) {
    // do something with result
}

// but subsequent loops don't
foreach($statement as $result) {
    // never called 
}

Есть ли способ переустановки заявления или поиска первой строки?

Ответы

Ответ 1

Я уверен, что это зависит от базы данных. Из-за этого вы должны избегать этого. Однако, я думаю, вы можете достичь того, чего хотите, включив буферизованные запросы. Если это не сработает, вы всегда можете вывести результат в массив с помощью fetchAll. Оба решения имеют последствия для производительности ваших приложений, поэтому дважды подумайте об этом, если набор результатов большой.

Ответ 2

Этот маленький класс, который я написал, обертывает PDOStatement. Он хранит только данные, которые извлекаются. Если это не сработает, вы можете переместить кеш для чтения и записи в файл.

// Wrap a PDOStatement to iterate through all result rows. Uses a 
// local cache to allow rewinding.
class PDOStatementIterator implements Iterator
{
    public
        $stmt,
        $cache,
        $next;

    public function __construct($stmt)
    {
        $this->cache = array();
        $this->stmt = $stmt;
    }

    public function rewind()
    {
        reset($this->cache);
        $this->next();
    }

    public function valid()
    {
        return (FALSE !== $this->next);
    }

    public function current()
    {
        return $this->next[1];
    }

    public function key()
    {
        return $this->next[0];
    }

    public function next()
    {
        // Try to get the next element in our data cache.
        $this->next = each($this->cache);

        // Past the end of the data cache
        if (FALSE === $this->next)
        {
            // Fetch the next row of data
            $row = $this->stmt->fetch(PDO::FETCH_ASSOC);

            // Fetch successful
            if ($row)
            {
                // Add row to data cache
                $this->cache[] = $row;
            }

            $this->next = each($this->cache);
        }
    }
}

Ответ 3

см. слайд 31 из этой презентации, вы можете сделать $statement->rewind(), если она применяется к буферизованному запросу. Если вы используете mysql, вы можете эмулировать буферизованные запросы, используя PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:

$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);

@NoahGoodrich указал вам на spl. Вот пример, который всегда работает:

$it = new ArrayIterator($stmt->fetchAll());

Ответ 4

Вероятно, вам захочется взглянуть на некоторые из классов PHP SPL, которые можно расширить, чтобы обеспечить доступ к объектам, подобным массиву.

  • Стандартная библиотека PHP (SPL) Я бы специально рекомендую посмотреть на ArrayIterator, ArrayObject и возможно, интерфейс Iterator.
  • <а href= "http://www.phpbuilder.com/manual/en/language.oop5.iterations.php" rel= "nofollow noreferrer" > Простой Учебник
  • <а href= "http://ramikayyali.com/archives/2005/02/25/iterators" rel= "nofollow noreferrer" > Другое Краткое руководство

Ответ 5

Спрошено давным-давно, но в настоящее время существует другое решение.

Метод PDOStatement::fetch() может получить второй параметр, ориентацию курсора, с одной из констант PDO::FETCH_ORI_*. Эти параметры действительны только в том случае, если PDOStatement создаются с атрибутом PDO::ATTR_CURSOR как PDO::CURSOR_SCROLL.

Таким образом вы можете перемещаться следующим образом.

$sql = "Select * From Tabela";
$statement = $db->prepare($sql, array(
    PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
));
$statement->execute();
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_NEXT);  // return next
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_PRIOR); // return previous
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_FIRST); // return first
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_LAST);  // return last
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_ABS, $n); // return to $n position
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_REL, $n); // return to $n position relative to current

Дополнительная информация в docs и предопределенные константы PDO.

Примечание: используется PDO::FETCH_BOTH, потому что это значение по умолчанию, просто настройте его для своего проекта.