I have a table similar to:
Item | Class | Qty | Loc |
---|---|---|---|
Apple | Fruit1 | 1 | N |
Apple | Fruit1 | 1 | NW |
Apple | Fruit2 | 0 | W |
Apple | Fruit3 | 1 | N |
Orange | Fruit1 | 10 | SE |
Orange | Fruit2 | 1 | SW |
I am trying to query all rows with the lowest Class
that has the smallest non-zero Qty
for each Item
. So if the same Item
has the same Qty
for multiple classes, it would select the lowest Class
(Fruit1
< Fruit2
< Fruit3
< ...). I've tried using something like:
SELECT A.*,
RANK() OVER(
PARTITION BY ITEM, CLASS
ORDER BY QTY ASC, CLASS ASC) AS item_rank
FROM fruits.info
WHERE QTY <> 0
to get a ranking to select, which isn't working. The results of the ranking should be:
Item | Class | Qty | Loc | item_rank |
---|---|---|---|---|
Apple | Fruit1 | 1 | N | 1 |
Apple | Fruit1 | 1 | NW | 1 |
Apple | Fruit3 | 1 | N | 2 |
Orange | Fruit1 | 10 | SE | 2 |
Orange | Fruit2 | 1 | SW | 1 |
I've would then use a nested select for item_rank = 1
:
SELECT B.* FROM (
SELECT A.*,
RANK() OVER(
PARTITION BY ITEM, CLASS
ORDER BY QTY ASC, CLASS ASC) AS item_rank
FROM fruits.info
) B
WHERE B.item_rank = 1
to get the final results, which should be:
Item | Class | Qty | Loc | item_rank |
---|---|---|---|---|
Apple | Fruit1 | 1 | N | 1 |
Apple | Fruit1 | 1 | NW | 1 |
Orange | Fruit2 | 1 | SW | 1 |
How can I structure my RANK()
in a way to achieve this? Is there a more efficient way?
CodePudding user response:
class
should only be used in ordering, not in partitioning. You want ranks for each item
, not for each pair of item
and class
.
The (easy to fix) mistake in your attempt was to include class
both in partition by
and in order by
; if you think about it for a second, that NEVER makes sense: if you partition by something, then further ordering by it (in each partition, where "it" is constant) makes no sense. Remove class
from partition by
and you should get what you need.