2

i'm using oracle sql developer. i have two tables

transactions:

╔════╤═══════╗
║ id │ value ║
╠════╪═══════╣
║ 1  │ 10    ║
╟────┼───────╢
║ 1  │ 20    ║
╟────┼───────╢
║ 2  │ 30    ║
╟────┼───────╢
║ 3  │ 40    ║
╚════╧═══════╝

and users:

╔════╤═════════╤═════╗
║ id │ country │ sex ║
╠════╪═════════╪═════╣
║ 1  │ Germany │ m   ║
╟────┼─────────┼─────╢
║ 2  │ Germany │ f   ║
╟────┼─────────┼─────╢
║ 3  │ France  │ m   ║
╚════╧═════════╧═════╝

i want to get max value for each country like this

╔════╤═════════╤═════╤══════════╗
║ id │ country │ sex │ maxvalue ║
╠════╪═════════╪═════╪══════════╣
║ 2  │ Germany │ f   │ 30       ║
╟────┼─────────┼─────┼──────────╢
║ 3  │ France  │ m   │ 40       ║
╚════╧═════════╧═════╧══════════╝

i know how to get max value for each user and join tables

SELECT u.*, max
FROM users u
LEFT JOIN
(SELECT id, max(value) as max
FROM transactions 
group by ID) t
on u.id = t.id;

what should i change to get a max value for each country?

riloth
  • 37
  • 7

6 Answers6

2

This might work:

SELECT id, country, sex, value AS maxvalue FROM (
    SELECT u.id, u.country, u.sex, COALESCE(t.value, 0) AS value
         , ROW_NUMBER() OVER ( PARTITION BY u.country ORDER BY t.value DESC NULLS LAST ) AS rn
      FROM users u LEFT JOIN transactions t
        ON u.id = t.id
) WHERE rn = 1;

This will get all the values for each country and rank them, then retrieve only the one with the top rank. If you want to get ties as well then use RANK() instead of ROW_NUMBER():

SELECT id, country, sex, value AS maxvalue FROM (
    SELECT u.id, u.country, u.sex, COALESCE(t.value, 0) AS value
         , RANK() OVER ( PARTITION BY u.country ORDER BY t.value DESC NULLS LAST ) AS rn
      FROM users u LEFT JOIN transactions t
        ON u.id = t.id
) WHERE rn = 1;

Hope this helps.

David Faber
  • 12,277
  • 2
  • 29
  • 40
1

The traditional method would not use a subquery, but simply join and group by:

SELECT u.country, MAX(t.value)
FROM users u LEFT JOIN
     transactions t
     ON u.id = t.id
GROUP BY u.country;
Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
1

This might get the required result

SELECT u.id, u.country, u.sex, MAX(t.value)
FROM users u 
LEFT JOIN transactions t ON u.id = t.id
GROUP BY u.id, u.country, u.sex;
Inaam ur Rehman
  • 470
  • 1
  • 6
  • 23
  • your code its not working, it doesnt shows maxvalue for each country – riloth Apr 28 '18 at 14:31
  • my query showing max value for **country** and **sex**, if you want only country wise value than remove u.id and u.sex from both the select and group by clause – Inaam ur Rehman Apr 28 '18 at 14:42
  • Error report - SQL Error: ORA-00979: not a GROUP BY expression 00979. 00000 - "not a GROUP BY expression" *Cause: *Action: – riloth Apr 28 '18 at 14:47
  • This error occurs when you don't have all the fields of selected clause in group by clause while using an aggregate function. see [this](https://stackoverflow.com/questions/13962772/not-a-group-by-expression-error) – Inaam ur Rehman Apr 28 '18 at 15:03
  • my real table is much bigger and i have there more than 2 sexes – riloth Apr 28 '18 at 15:07
  • so what? more than two sexes and table size (rows in table) does not matter. – Inaam ur Rehman Apr 28 '18 at 15:13
1

You have to first find the max per country and the do another join for the sex, like this:

SELECT u.*, t.value
FROM transactions t
INNER JOIN users u ON t.id = u.id
INNER JOIN
(SELECT us.country, MAX(tr.value) AS max_value
 FROM transactions tr
 INNER JOIN users us ON tr.id = us.id
 GROUP BY us.country) sub ON t.value = sub.value AND u.country = sub.country
kjmerf
  • 4,275
  • 3
  • 21
  • 29
1

Try this.

select tmp.country, tmp.maxvalue, tmp.id, users.sex from (
select users.country as country, max(transactions.value) as maxvalue, max(users.id) as id 
from users
inner join transactions on users.id = transactions.id
group by users.country) tmp
inner join users on tmp.id = users.id;

Demo: http://www.sqlfiddle.com/#!4/5f476/27/0

DxTx
  • 3,049
  • 3
  • 23
  • 34
1
select * from (
SELECT t.ID, u.COUNTRY, T.VALUE, 
row_number() over(partition by u.country order by t.value desc) rn
FROM USERS u , transactions t
where u.id = t.id)
where rn = 1
Leo
  • 868
  • 1
  • 13
  • 32