简体   繁体   中英

Select a row used for GROUP BY

I have this table:

id | owner | asset | rate
-------------------------
1  | 1     | 3     | 1
2  | 1     | 4     | 2
3  | 2     | 3     | 3
4  | 2     | 5     | 4

And i'm using

SELECT asset, max(rate)
FROM test 
WHERE owner IN (1, 2)
GROUP BY asset
HAVING count(asset) > 1
ORDER BY max(rate) DESC

to get intersection of assets for specified owners with best rate.

I also need id of row used for max(rate), but i can't find a way to include it to SELECT. Any ideas?

Edit:

I need

  • Find all assets that belongs to both owners (1 and 2)
  • From the same asset i need only one with the best rate (3)
  • I also need other columns (owner) that belongs to the specific asset with best rate

I expect the following output:

id | asset | rate
-------------------------
3  | 3     | 3

Oops, all 3s, but basically i need id of 3rd row to query the same table again, so resulting output (after second query) will be:

id | owner | asset | rate
-------------------------
3  | 2     | 3     | 3

Let's say it's Postgres, but i'd prefer reasonably cross-DBMS solution.

Edit 2:

Guys, i know how to do this with JOINs. Sorry for misleading question, but i need to know how to get extra from existing query. I already have needed assets and rates selected, i just need one extra field among with max(rate) and given conditions if it's possible.

Another solution that might or might not be faster than a self join (depending on the DBMS' optimizer)

SELECT id, 
       asset,
       rate,
       asset_count
FROM (
    SELECT id,
           asset, 
           rate,
           rank() over (partition by asset order by rate desc) as rank_rate,
           count(asset) over (partition by null) as asset_count
    FROM test 
    WHERE owner IN (1, 2)
) t
WHERE rank_rate = 1
ORDER BY rate DESC

This first searches for rows with the maximum rate per asset. Then it takes the highest id per asset, and selects that:

select  *
from    test
inner join
        (
        select  max(id) as MaxIdWithMaxRate
        from    test
        inner join
                (
                select  asset
                ,       max(rate) as MaxRate
                from    test 
                group by
                        asset
                ) filter
        on      filter.asset = test.asset
                and filter.MaxRate = test.rate
        group by
                asset
        ) filter2
on      filter.MaxIdWithMaxRate = test.id

If multiple assets share the maximum rate, this will display the one with the highest id.

You are dealing with two questions and trying to solve them as if they are one. With a subquery, you can better refine by filtering the list in the proper order first (max(rate)), but as soon as you group, you lose this. As such, i would set up two queries (same procedure, if you are using procedures, but two queries) and ask the questions separately. Unless... you need some of the information in a single grid when output.

I guess the better direction to head is to have you show how you want the output to look. Once you bake the input and the output, the middle of the oreo is easier to fill.

SELECT b.id, b.asset, b.rate
from
(
SELECT asset, max(rate) maxrate
FROM test  
WHERE owner IN (1, 2) 
GROUP BY asset 
HAVING count(asset) > 1 
) a, test b
WHERE a.asset = b.asset
AND a.maxrate = b.rate
ORDER BY b.rate DESC 

You don't specify what type of database you're running on, but if you have analytical functions available you can do this:

select id, asset, max_rate
from (
   select ID, asset, max(rate) over (partition by asset) max_rate, 
   row_number() over (partition by asset order by rate desc) row_num
   from test
   where owner in (1,2)
) q
where row_num = 1

I'm not sure how to add in the "having count(asset) > 1" in this way though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM