Pg result seek: примеры (PHP)
pg_result_seek(PgSql\Result $result, int $row): boolОписание функции pg_result_seek
Функция pg_result_seek используется для перемещения внутреннего указателя на произвольную строку в результате запроса к базе данных PostgreSQL.
Эта функция применяется, когда требуется повторно обработать определенные строки из уже полученного результата, не выполняя запрос заново. Это может быть полезно для навигации по данным, повторного извлечения строк или реализации пользовательской логики перебора.
- $result (PgSql\Result|resource) - Обязательный. Ресурс результата запроса, возвращаемый функциями
pg_query,pg_query_paramsилиpg_execute. - $row (int) - Обязательный. Номер строки, на которую нужно переместить внутренний указатель. Нумерация строк начинается с 0.
Функция возвращает true в случае успеха и false в случае неудачи (например, при попытке установить указатель на несуществующую строку).
Короткие примеры использования
$conn = pg_connect("host=localhost dbname=test user=postgres");
$result = pg_query($conn, "SELECT id, name FROM products ORDER BY id");
// Перемещаем указатель на 3-ю строку (индекс 2)
$seekResult = pg_result_seek($result, 2);
var_dump($seekResult);
// Извлекаем текущую строку (теперь это 3-я строка)
$row = pg_fetch_assoc($result);
print_r($row);bool(true)
Array
(
[id] => 3
[name] => Product C
)$result = pg_query($conn, "SELECT id FROM products LIMIT 5");
$seekResult = pg_result_seek($result, 10);
var_dump($seekResult);bool(false)
Альтернативные функции в PHP
Можно сразу извлекать строку по индексу, используя pg_fetch_row, pg_fetch_assoc или pg_fetch_array с указанием номера строки в качестве второго аргумента. Этот подход не меняет внутренний указатель результата.
$row = pg_fetch_assoc($result, 3); // Получить 4-ю строкуИспользование pg_fetch_all позволяет получить все строки как массив, после чего навигация осуществляется стандартными средствами PHP.
$allRows = pg_fetch_all($result);
$specificRow = $allRows[2]; // Доступ к 3-й строкеПредпочтения: pg_result_seek удобна для сценариев с последовательным доступом к разным частям результата. Прямое извлечение по индексу эффективнее для разовых операций. Получение всего массива потребляет больше памяти, но упрощает сложную навигацию.
Аналоги в других языках и СУБД
В psycopg2 курсор по умолчанию представляет собой итератор, но можно использовать scroll() для перемещения.
cursor.execute("SELECT * FROM products")
cursor.scroll(2, mode='absolute') # Перемещение к 3-й записи
row = cursor.fetchone()Модуль 'pg' обычно возвращает все строки сразу в массиве. Навигация происходит по этому массиву.
const result = await pool.query('SELECT * FROM products');
const thirdRow = result.rows[2];Вместо позиционирования на клиенте часто используют OFFSET в SQL-запросе.
-- Получить 3-ю строку (нумерация с 0)
SELECT * FROM products LIMIT 1 OFFSET 2;Отличия: pg_result_seek работает на стороне клиента с уже полученными данными, в то время как OFFSET и LIMIT выполняются на сервере. Это влияет на производительность при работе с большими объемами данных.
Типичные ошибки
$conn = pg_connect("host=localhost dbname=test");
// ОШИБКА: Первый аргумент - не результат запроса
$seekResult = pg_result_seek($conn, 0);
var_dump($seekResult);bool(false)
$result = pg_query($conn, "SELECT id FROM products LIMIT 2");
$seekResult = pg_result_seek($result, 5); // Всего 2 строки
if (!$seekResult) {
echo "Не удалось переместить указатель. Проверьте номер строки.";
}$result = pg_query($conn, "SELECT id FROM products WHERE 1=0");
$seekResult = pg_result_seek($result, 0); // Результат пуст
var_dump($seekResult);bool(false)
Изменения в последних версиях PHP
В PHP 8.0 тип параметра $result был изменен с resource на PgSql\Result в рамках общей политики типизации ресурсов. Старый псевдоним типа resource по-прежнему принимается для обратной совместимости, но рекомендуется использовать новый тип.
Начиная с PHP 8.1, при передаче некорректного типа аргумента генерируется ошибка TypeError уровня E_WARNING, а не возвращается false молча, как в более ранних версиях.
Значительных изменений в поведении функции в версиях PHP 8.2 и 8.3 не было.
Расширенные примеры использования
$result = pg_query($conn, "SELECT id, name FROM products ORDER BY id");
$totalRows = pg_num_rows($result);
// Проход вперед
for ($i = 0; $i < $totalRows; $i++) {
pg_result_seek($result, $i);
$row = pg_fetch_assoc($result);
echo $row['id'] . ': ' . $row['name'] . "\n";
}
// Проход в обратном порядке
for ($i = $totalRows - 1; $i >= 0; $i--) {
pg_result_seek($result, $i);
$row = pg_fetch_assoc($result);
echo $row['id'] . ': ' . $row['name'] . "\n";
}$result = pg_query($conn, "SELECT id, status FROM orders");
$pendingOrders = [];
$totalRows = pg_num_rows($result);
for ($i = 0; $i < $totalRows; $i++) {
pg_result_seek($result, $i);
$row = pg_fetch_assoc($result);
if ($row['status'] === 'pending') {
$pendingOrders[] = $row;
// Вернуться и проверить предыдущую строку?
// pg_result_seek($result, $i-1); // Пример условного возврата
}
}
print_r($pendingOrders);$queryCache = [];
function getCachedRow($result, $index) {
global $queryCache;
$resultId = (int)$result; // Упрощенный идентификатор
if (!isset($queryCache[$resultId][$index])) {
if (pg_result_seek($result, $index)) {
$queryCache[$resultId][$index] = pg_fetch_assoc($result);
}
}
return $queryCache[$resultId][$index] ?? null;
}
$result = pg_query($conn, "SELECT * FROM large_table LIMIT 100");
$row10 = getCachedRow($result, 9); // Загрузит и закэширует
$row10Again = getCachedRow($result, 9); // Возьмет из кэша$result = pg_query($conn, "SELECT * FROM log_messages ORDER BY created_at");
// Обработали первые 5 записей
for ($i = 0; $i < 5; $i++) {
$row = pg_fetch_assoc($result);
processLogEntry($row);
}
// Позже вернулись к 3-й записи для повторной обработки
if (pg_result_seek($result, 2)) {
$specificLog = pg_fetch_assoc($result);
reanalyzeEntry($specificLog);
}
// Продолжили с 6-й записи (указатель сейчас на 4 после последнего fetch)
// Нужно снова переместить указатель
pg_result_seek($result, 5);
while ($row = pg_fetch_assoc($result)) {
processLogEntry($row);
}