При доступе к сообщению мне нужно, помимо возврата информации об этом сообщении, вернуть предыдущий, если он существует, и следующий.
Я хотел бы знать, есть ли способ выбрать MAX(id)
и MIN(id)
в одном запросе/выборе, передав условие для каждого из них. Пример того, что я пытаюсь сделать в Laravel, и я напишу это на SQL, чтобы упростить задачу.
Ларавель:
$query = Post::query();
$query = $query->from('posts')->select(DB::raw('MAX(id), MIN(id)'))->whereRaw("id < {$id} and id > {$id}")->first();
SQL:
select MAX(id), MIN(id) from `posts` where id < 5 and id > 5 limit 1
Переменная id — это значение идентификатора сообщения. В этом примере он имеет значение 5. Я делаю запрос, чтобы получить MAX и MIN, относящиеся к этому идентификатору, но мне также нужно получить информацию о публикации, к которой обратился пользователь.
В БД есть пост id номер 4 и номер 6. То есть мне нужно получить информацию из постов номер 4, 5 и 6 в этом примере.
Условие where никогда не будет true
, но я не могу использовать or
. Первое условие для MAX
, а второе для MIN
. Если я использую or
, самый большой идентификатор будет получен из БД.
Мне нужно получить минимальное и максимальное значение по сравнению со значением. То есть, как я объяснил выше. Если id равен 5, мне нужно получить самый большой существующий id() ниже этого значения, и мне нужно получить наименьшее значение над ним. В моем случае из информации, которая есть у меня в БД, это будут идентификаторы 4, 5 и 6.
Возможно ли это за одну консультацию или мне действительно нужно сделать больше одной?
Да, но я не могу использовать or
. Первое условие для MAX
, а второе для MIN
. Если я использую or
. Самый большой идентификатор будет исходить из БД
минимальный воспроизводимый пример сделал бы это намного яснее.
Я не знаю, как быть яснее. Мне нужно получить минимальное и максимальное значение по сравнению со значением. То есть, как я объяснил выше. Если id равен 5, мне нужно получить самый большой существующий id() ниже этого значения, и мне нужно получить наименьшее значение над ним. В моем случае из информации, которая есть у меня в БД, это будут идентификаторы 4, 5 и 6.
Образец табличных данных и ожидаемый результат - все в виде форматированного текста (без изображений, без ссылок).
Функции LEAD() и LAG() в MySQL используются для получения предыдущего и последующего значения любой строки в ее разделе.
Попробуй это:
SELECT ID,
LAG (id) OVER (ORDER BY NULL) ONE_SHIFT_FORWARD,
LEAD (id) OVER (ORDER BY NULL) ONE_SHIFT_BACKWARD
FROM POSTS
ORDER BY ID ASC;
SELECT *
FROM ( SELECT ID,
LAG (id) OVER (ORDER BY NULL) ONE_SHIFT_FORWARD,
LEAD (id) OVER (ORDER BY NULL) ONE_SHIFT_BACKWARD
FROM POSTS
ORDER BY ID ASC)
WHERE id = 5;
Очень хорошо, в SQL это работает, но в Laravel я не смог воспроизвести это. Я исследовал, тестировал, но таким образом выдает ошибку «ASC или DESC». Но большое спасибо за альтернативу.
Попробуйте удалить слово ASC. Только писать: ORDER BY ID (без слова ASC, что означает ПО ВОЗРАСТУ).
Да, вы можете сделать это с case-when
select MAX(
CASE
WHEN id < 5 THEN id
ELSE NULL
END
), MIN(
CASE
WHEN id > 5 THEN id
ELSE NULL
END
)
from `posts`
where id <> 5
РЕДАКТИРОВАТЬ
Эквивалент Laravel, как поделился Габриэль Эду в разделе комментариев:
$query = Post::query();
$query = $query->from('posts')->
select(DB::raw("MAX(CASE WHEN id < {$id} THEN id ELSE null END), MIN(CASE WHEN id > {$id} THEN id ELSE null END)"))->first();
Очень хорошо, но я этого не знал. Это очень помогло. Так как это для Laravel, я добавлю его сюда, чтобы помочь кому-то еще. КОД: $query = Post::query(); $query = $query->from('posts')->select(DB::raw("MAX(CASE WHEN id < {$id} THEN id ELSE null END), MIN(CASE WHEN id > {$id} THEN id ELSE null END)"))->first();
@GabrielEdu спасибо за кусок кода Laravel, добавил его в мой ответ. Если этот ответ решил вашу проблему, вы можете принять его как правильный ответ.
Я думаю, что предложение LIMIT 1 может быть удалено из запроса.
@UltraCommit да, ваше наблюдение верно, удалил его.
Вы можете использовать lead
и lag
для доступа к значениям до и после текущей строки.
Затем вы можете использовать их для выбора сообщения с заданным идентификатором и значениями до и после в одном выборе.
Следующий запрос
select *
from (
select
p.*,
lead(id) over(order by id) _lead,
lag(id) over(order by id) _lag
from post p
) x
where 23 in (id, _lead, _lag);
приводит к
Со следующей настройкой:
Схема (MySQL v8.0)
create table post (
id integer,
text varchar(50)
);
insert into post(id, text)
values
( 10, 'ten'),
( 15, 'fifteen'),
( 23, 'twentythree'),
( 24, 'twentyfour'),
( 50, 'fifty');
Очень хорошо, в SQL это работает, но в Laravel я не смог воспроизвести это. Я исследовал, тестировал, но таким образом выдает ошибку «ASC или DESC». Но большое спасибо за альтернативу.
id < 5 and id > 5
никогда не бывает ИСТИННЫМ.