Is there a way in Postgresql to write a query which groups rows based on a column with a limit without discarding additional rows.
Say I've got a table with three columns id, color, score
with the following rows
1 red 10.0
2 red 7.0
3 red 3.0
4 blue 5.0
5 green 4.0
6 blue 2.0
7 blue 1.0
I can get a grouping based on color with window functions with the following query
SELECT * FROM (
SELECT id, color, score, rank()
OVER (PARTITION BY color ORDER BY score DESC)
FROM grouping_test
) AS foo WHERE rank <= 2;
with the result
id | color | score | rank
----+-------+-------+------
4 | blue | 5.0 | 1
6 | blue | 2.0 | 2
5 | green | 4.0 | 1
1 | red | 10.0 | 1
2 | red | 7.0 | 2
which discards item with ranks > 2. However what I need is a result like
1 red 10.0
2 red 7.0
4 blue 5.0
6 blue 2.0
5 green 4.0
3 red 3.0
7 blue 1.0
With no discarded rows.
Edit: To be more precise about the logic I need:
Continue as long as pairs with the same color can be found, then order whats left by descending score.
The import statements for a test table can be found here. Thanks for your help.
It can be done using two nested window functions
SELECT
id
FROM (
SELECT
id,
color,
score,
((rank() OVER color_window) - 1) / 2 AS rank_window_id
FROM grouping_test
WINDOW color_window AS (PARTITION BY color ORDER BY score DESC)
) as foo
WINDOW rank_window AS (PARTITION BY (color, rank_window_id))
ORDER BY
(max(score) OVER rank_window) DESC,
color;
With 2
being the parameter of the group size.
You can do ORDER BY (rank <= 2) DESC
to get the rows with rank<=2 above all else:
SELECT id,color,score FROM (
SELECT id, color, score, rank()
OVER (PARTITION BY color ORDER BY score DESC),
max(score) OVER (PARTITION BY color) mx
FROM grouping_test
) AS foo
ORDER BY
(rank <= 2) DESC,
CASE WHEN rank<=2 THEN mx ELSE NULL END DESC,
id;
http://sqlfiddle.com/#!12/bbcfc/109
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With