Задать вопрос
@shupike

Как в выборке sql обратиться к предыдущей записи?

Всем доброго дня! Подскажите, пожалуйста, по php - формирую запрос к базе, пробегаю по выборке (если упростить задачу - по серийному номеру оборудования ищу записи в таблицах и вытаскиваю последнюю дату - то есть как бы из истории перемещений этого оборудования нахожу его последнее местонахождение). Но мне нужно не только последнюю дату и местоположение получить, а и предыдущего владельца. Скажем, выглядят итоги запроса вот так:
Устройство | Серийный | Дата получения | Местоположение
Ноутбук | 12349647 | 21.03.25 | Склад
Ноутбук | 12349647 | 15.01.25 | Сотрудник_1
Ноутбук | 12349647 | 30.08.24 | Склад
Ноутбук | 12349647 | 22.05.24 | Сотрудник_2

Я просто вставляю order by date (поле даты) и забираю последнюю строчку. Но нужно еще и зацепить предыдущего владельца, в данном примере - Сотрудника_1. Вот не пойму, как это сделать... Я посчитал число перемещений по каждой единице оборудования:
$count=0;
while ($row2 = pg_fetch_row($result2)) {
$last_date = $row2[2];
$last_owner = $row2[1];
$count=$count+1;
}
Но как внутри while обратиться не к текущей строке, а еще и к предыдущей в выборке? Заранее огромное спасибо за советы.
  • Вопрос задан
  • 316 просмотров
Подписаться 2 Простой Комментировать
Решения вопроса 3
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
ORDER BY date DESC 
LIMIT 2

Получите последнюю и предпоследнюю записи.
Ответ написан
Комментировать
@Akina
Сетевой и системный админ, SQL-программист.
Я просто вставляю order by date (поле даты) и забираю последнюю строчку.

Глупо.

Используй ORDER BY date DESC - и тогда можно, во-первых, брать первую строку, а не мотать вниз до последней, во-вторых, нужная "предыдущая" строка при обратной сортировке будет "следующая" - ну то есть вторая.

PS. Дата - ненадёжный критерий сортировки. За один день комп могут сдать на склад и выдать другому товарищу - и будешь ты гадать, какая из двух записей актуальная, а какая для неё предыдущая. Я уж не говорю о вводах и корректировках "задним числом".
Ответ написан
ipatiev
@ipatiev Куратор тега PHP
Потомок старинного рода Ипатьевых-Колотитьевых
Чтобы внутри while обратиться к предыдущей записи, надо в самом низу цикла записывать текущую строку в переменную.
Тогда при следующей итерации цикла в ней будет предыдущая запись.
С любовью, Капитан Очевидность.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
@d-stream
Готовые решения - не подаю, но...
Изучаем LAG и LEAD потом выясняем - есть ли они для своего, а не абстрактного sql
И если есть - наслаждаемся.
Ответ написан
@alexalexes
Устройство | Серийный | Дата получения | Местоположение
Ноутбук | 12349647 | 21.03.25 | Склад
Ноутбук | 12349647 | 15.01.25 | Сотрудник_1
Ноутбук | 12349647 | 30.08.24 | Склад
Ноутбук | 12349647 | 22.05.24 | Сотрудник_2

Такой способ записи с опорой на дату для построения исторической цепочки архитектурно не устройчив.
Чтобы историческая цепочка стала устойчивой, нужно вводить указатель на следующую или предыдущую запись.
ID | Устройство | Серийный | Дата получения | Местоположение | Следующий ID
11 | Ноутбук | 12349647 | 21.03.25 | Склад | null
8 | Ноутбук | 12349647 | 15.01.25 | Сотрудник_1 | 11
5 | Ноутбук | 12349647 | 30.08.24 | Склад | 8
1 | Ноутбук | 12349647 | 22.05.24 | Сотрудник_2 | 5

При всех CRUD операциях работы с историческим списком нужно корректно записывать next_id в предыдущей записи.
Можно произвольно перезаписывать все не служебные поля (кроме id и next_id), вплоть до серийника, и это не разрушит историческую цепочку.
Последняя запись в исторической цепочке всегда будет next_id is null.
Чтобы действительно корректно получать историческую цепочку, нужен рекурсивный запрос, но в простейших случаях достаточно сортировать цепочку по next_id.
Ответ написан
@shupike Автор вопроса
Вы знаете, я, наверное, странноватый человек :-), но сделал в итоге вообще не так:
////////
$result = pg_query($conn,"select name,model,inventory_code,s_n,device_type_code from public.main where device_type_code=1 order by main.s_n");
if (!$result) {
echo "An error occurred.\n";
exit;
}

echo "
Название Модель Инвентарный номер Поступил Число перемещений
";
while ($row = pg_fetch_row($result)) {
$serial_number = $row[3]; //записываем значение серийного номера в переменную $serial_number
//и создаем вложенный запрос, в котором по каждому ноутбуку (по серийному номеру)
//будем извлекать историю перемещений

$result2 = pg_query($conn,"select main.s_n, employers.employer, history.date from main inner join (employers inner join history on employers.employer_code = history.device_code where s_n='$serial_number' order by history.date");>
//полученные результаты сортируем по дате и подбираем самую свежую дату
$count=0; //счетчик перемещений по каждому ноутбуку
while ($row2 = pg_fetch_row($result2)) { //идем по выборке
$last_date = $row2[2]; //собираем дату
$last_owner = $row2[1]; //и владельца; последняя такая строка и будет последним владельцем ноутбука
$count=$count+1; //считаем число перемещений устройства
}
$discount=$count-2; //спускаемся до предшественника
//теперь смотрим нахождение ноутбука по последней дате - если это был Склад, то выводим в таблицу, если нет - пропускаем
if ($last_owner == "Склад") {
if($count=='1') {
$owner_prev="Не было перемещений";
}
else {
$row_prev = pg_fetch_row($result2,$discount);
$owner_prev = $row_prev[1];
}
echo "
$row[0] $row[1] $row[2] $last_date $count $owner_prev
";

}
}
///////
И это работает - для контроля вывел еще один столбец (временно) с числом перемещений по каждой позиции. Предложенные варианты с DESC LIMIT2 не помогли, надо сказать.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы