#sql #postgresql
#sql #postgresql
Вопрос:
Я ищу помощь с запросом postgresql.
Пример входных данных выглядит следующим образом:
pk name
=========================
1 | notebook cz-2001
2 | notebook cz-2002
3 | notebook cz-2003
4 | notebook cz-2003
5 | notebook cz-2003
6 | notebook cz-2004
7 | notebook cz-2004
8 | notebook cz-2004
9 | notebook cz-2004
10 | notebook cz-2005
11 | notebook cz-2006
12 | notebook cz-2007
13 | notebook cz-2008
14 | notebook cz-2009
Некоторые строки имеют одинаковое значение в столбце name (notebook cz-2003, notebook cz-2004)
Я могу получить одно максимальное значение pk для сгруппированных имен с помощью этого запроса:
select * from test_group where pk in
(
select max(pk) from test_group group by name order by name
)
Результат:
pk name
=========================
1 | notebook cz-2001
2 | notebook cz-2002
5 | notebook cz-2003
9 | notebook cz-2004
10 | notebook cz-2005
11 | notebook cz-2006
12 | notebook cz-2007
13 | notebook cz-2008
14 | notebook cz-2009
но я понятия не имею, и это мой вопрос, как получить, например, два (три, четыре …) наивысших значения pk для сгруппированных имен.
Ожидаемый результат, например, для двух самых высоких pk:
pk name
=========================
1 | notebook cz-2001
2 | notebook cz-2002
4 | notebook cz-2003
5 | notebook cz-2003
8 | notebook cz-2004
9 | notebook cz-2004
10 | notebook cz-2005
11 | notebook cz-2006
12 | notebook cz-2007
13 | notebook cz-2008
14 | notebook cz-2009
Не могли бы вы дать мне несколько советов, как этого добиться?
Спасибо
JP
Ответ №1:
Для этого можно использовать row_number()
функцию window:
SELECT pk, name
FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY name ORDER BY pk DESC)
FROM my_table
) s
WHERE row_number <= 2 -- or any other value
row_number()
оконная функция добавляет номер строки в определенную упорядоченную группу. Здесь ваша группа — это name
столбец, а порядок — по pk
(по убыванию, потому что вы хотите, чтобы сначала считались самые высокие числа).
С WHERE
помощью предложения вы можете отфильтровать первые n записей (которые были пронумерованы 1, 2, …) или любые другие элементы, которые вам нравятся.
Ответ №2:
Одним из методов являются оконные функции:
select tg.*
from (select tg.*,
row_number() over (partition by name order by pk desc) as seqnum
from test_group tg
) tg
where seqnum <= ?;
Другой метод — более соответствующий вашему текущему подходу — это коррелированный подзапрос:
select tg.*
from test_group tg
where tg.pk >= any (select tg2.pk
from test_group tg2
where tg2.name = tg.name
);