@immelnikoff
Изучаю БД

Как реализовать first_value(field) с фильтром на field внутри окна?

Имеется два запроса на PostgreSQL 15, формирующих аналогичные результаты:
select
	id,
	banner_id,
	max(banner_id) filter (where banner_id in (13,14,15,17)) over(partition by id) as max_banner_id_1,
	max(banner_id) filter (where banner_id in (4,177,178)) over(partition by id) as max_banner_id_2
from (values (1,13),(1,null),(1,15),(1,null),(1,13),(1,17),(1,14),(1,177),(1,178),(1,4),(1,177)) as T(id, banner_id)
order by banner_id

select
	id,
	banner_id,
	max(case when banner_id in (13,14,15,17) then banner_id end) over(partition by id) as max_banner_id_1,
	max(case when banner_id in (4,177,178) then banner_id end) over(partition by id) as max_banner_id_2
from (values (1,13),(1,null),(1,15),(1,null),(1,13),(1,17),(1,14),(1,177),(1,178),(1,4),(1,177)) as T(id, banner_id)
order by banner_id

63f0acb139f33807811716.png
С ними всё понятно.
Но есть вопрос: как реализовать аналогичную логику, но не с помощью max(), а с помощью first_value() ?
Конструкция filter (where ...) допустима только для агрегирующих функций, поэтому остается 2-й вариант:
select
	id,
	banner_id,
	first_value(case when banner_id in (13,14,15,17) then banner_id end) over(partition by id order by banner_id desc) as max_banner_id_1,
	first_value(case when banner_id in (4,177,178) then banner_id end) over(partition by id order by banner_id desc) as max_banner_id_2
from (values (1,13),(1,null),(1,15),(1,null),(1,13),(1,17),(1,14),(1,177),(1,178),(1,4),(1,177)) as T(id, banner_id)
order by banner_id

63f0b0cc3b231719821266.png
Как видно, результат не тот, что ожидается.
Как реализовать это с подзапросами я понимаю.
Вопрос в том, можно ли это реализовать не прибегая к вложенностям?
Может это можно сделать на других СУБД?
  • Вопрос задан
  • 239 просмотров
Решения вопроса 1
@Akina
Сетевой и системный админ, SQL-программист.
SELECT 
  *,
  FIRST_VALUE(CASE WHEN banner_id IN (13,14,15,17)
                   THEN banner_id 
                   END) OVER (PARTITION BY id
                              ORDER BY CASE WHEN banner_id IN (13,14,15,17)
                                            THEN banner_id 
                                            END DESC NULLS LAST) max_banner_id_1,
  FIRST_VALUE(CASE WHEN banner_id IN (4,177,178)
                   THEN banner_id 
                   END) OVER (PARTITION BY id
                              ORDER BY CASE WHEN banner_id IN (4,177,178)
                                            THEN banner_id
                                            END DESC NULLS LAST) max_banner_id_2
FROM test
ORDER BY banner_id
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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