Возможно ли перемотать результат 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
, потому что это значение по умолчанию, просто настройте его для своего проекта.