简体   繁体   中英

Filter rows from oracle sql table using max value of a column

I am learning oracle SQL, and I have a table like the following:

+--------+--------+------------------------+
| name   | nation | count                  |
+--------+--------+------------------------+
| Ruben  | UK     | 2                      |
| Ruben  | EEUU   | 16                     |
| Cesar  | UK     | 21                     |
| Cesar  | EEUU   | 12                     |
| Cesar  | FRANCE | 4                      |
| John   | FRANCE | 3                      |
| John   | UK     | 7                      |
| ....   | ..     | ..                     |
+--------+--------+------------------------+

The table above represents an inline view I created with a query. As you can see, the table groups by name and by nation and do some count. I want to filter the table using the count column to have something like this:

+--------+--------+
| name   | nation |
+--------+--------+
| Ruben  | EEUU   |
| Cesar  | UK     |
| John   | UK     |
| ....   | ..     |
+--------+--------+  

As you can see, for each name I want to choose the nation based on the count.

You can do this with another level of inner query. Something like:

select name, nation
from (
  select name, nation, cnt,
    row_number() over (partition by name, nation order by cnt desc) as rn
  from (
    select name, nation, count(*) as cnt
    from <your table>
  )
)
where rn = 1;

The row_number() analytic adds a pseudo column to the innermost query that ranks the row with the highest count as 1, for each name/nation; the outermost query then only looks at those ranked first.

You need to decide what to do about ties - if two nation/name rows have the same count, you could show both by using rank() instead of row_number() ; or you could decide which one to choose by adding another column to the order by clause. At the moment, if there are two the same, it will only show you one of them - and which it shows is rather arbitrary.

Use keep analytic keyword:

select name, min(nation) keep (dense_rank last order by cnt)
from (select name, nation, count(*) as cnt
      from /* your data source */
      group by name, nation)
group by name
  1. min(nation) - min is meaningless in this case but you must keep it (doesn't work without)
  2. keep - keeps only one result of nation
  3. dense_rank last says to pick up the last element
  4. order by cnt says how to define the order of elements

In the end it will make for every name the nation with the biggest count. The same result can be achieved with

select name, min(nation) keep (dense_rank first order by cnt desc)

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