Getting distinct values with the highest value in a specific column - sql

How can I get the highlighted rows from the table below in SQL? (Distinct rows based on User name with the highest Version are highlighted)
In case you need plain text table:
+----+-----------+---+
| 1 | John | 1 |
+----+-----------+---+
| 2 | Brad | 1 |
+----+-----------+---+
| 3 | Brad | 3 |
+----+-----------+---+
| 4 | Brad | 2 |
+----+-----------+---+
| 5 | Jenny | 1 |
+----+-----------+---+
| 6 | Jenny | 2 |
+----+-----------+---+
| 7 | Nick | 4 |
+----+-----------+---+
| 8 | Nick | 1 |
+----+-----------+---+
| 9 | Nick | 3 |
+----+-----------+---+
| 10 | Nick | 2 |
+----+-----------+---+
| 11 | Chris | 1 |
+----+-----------+---+
| 12 | Nicole | 2 |
+----+-----------+---+
| 13 | Nicole | 1 |
+----+-----------+---+
| 14 | James | 1 |
+----+-----------+---+
| 15 | Christine | 1 |
+----+-----------+---+
What I have so far is (works for one user)
SELECT USER, VERSION
FROM TABLE
WHERE USER = 'Brad'
AND VERSION = (SELECT MAX(VERSION ) FROM TABLE WHERE USER= 'Brad')

SELECT USER, max(VERSION) VERSION
FROM TABLE GROUP BY USER;
If you need an ID then
SELECT ID, USER, VERSION FROM (
SELECT ID, USER, VERSION,
RANK() OVER(PARTITION BY USER ORDER BY VERSION DESC) RNK
FROM TABLE
) WHERE RNK = 1;
if you have
| 2 | Brad | 5 |
+----+-----------+---+
| 3 | Brad | 3 |
+----+-----------+---+
| 4 | Brad | 5 |
The query with RANK gives you both users
| 2 | Brad | 5 |
+----+-----------+---+
| 4 | Brad | 5 |
If you need only one row then replace RANK() with ROW_NUMBER()
In your query you're using AND VERSION = (SELECT MAX(VERSION ) FROM TABLE WHERE USER= 'Brad') which is equivalent to RANK() (all rows with the max VERSION)

The first_value analytic function should do the trick:
SELECT DISTINCT FIRST_VALUE (id)
OVER (PARTITION BY name ORDER BY version DESC)
name,
FIRST_VALUE (version)
OVER (PARTITION BY name ORDER BY version DESC)
FROM my_table
Another way to go would be to use the row_number function:
SELECT id, name, version
FROM (SELECT id, name, version
ROW_NUMBER() OVER (PARTITION BY name ORDER BY version DESC) rn
FROM my_table)
WHERE rn = 1
Not sure which I prefer, personally. They each have their merit and their ugliness.

this might help you :
select id, user, version
from
(
select id, user, version, row_number() over (partition by user order by version desc) rownum
from yourtable
) as t
where t.rownum = 1
sql fiddle

Related

Get the position of X user in the ranking

I have these tables
RANKING
+-----------+----------+
| id_users | points |
+-----------+----------+
| 1 | 27 | //3rd
| 2 | 55 | //1st
| 3 | 9 | //5th
| 4 | 14 | //4th
| 5 | 38 | //2nd
+-----------+----------+
I would like to retrieve user's data along with its ranking position, filtering by id. So for example if I want info for id 3 I should get
+----------+--------|---------------+
| id_users | points | rank_position |
+----------+--------|---------------+
| 3 | 9 | 5 |
+----------+--------|---------------+
My query actually has the following:
SELECT
ROW_NUMBER() OVER (ORDER BY points ASC) AS RowNum,
id_users
FROM
RANKING
And I don't know how to continue
If you use ROW_NUMBER(), you need to use a subquery:
SELECT r.*
FROM (SELECT r.*,
ROW_NUMBER() OVER (ORDER BY points ASC) AS RowNum
FROM RANKING r
) r
WHERE id_users = 5;

Combine PARTITION BY and GROUP BY

I have a (mssql) table like this:
+----+----------+---------+--------+--------+
| id | username | date | scoreA | scoreB |
+----+----------+---------+--------+--------+
| 1 | jim | 01/2020 | 100 | 0 |
| 2 | max | 01/2020 | 0 | 200 |
| 3 | jim | 01/2020 | 0 | 150 |
| 4 | max | 02/2020 | 150 | 0 |
| 5 | jim | 02/2020 | 0 | 300 |
| 6 | lee | 02/2020 | 100 | 0 |
| 7 | max | 02/2020 | 0 | 200 |
+----+----------+---------+--------+--------+
What I need is to get the best "combined" score per date. (With "combined" score I mean the best scores per user and per date summarized)
The result should look like this:
+----------+---------+--------------------------------------------+
| username | date | combined_score (max(scoreA) + max(scoreB)) |
+----------+---------+--------------------------------------------+
| jim | 01/2020 | 250 |
| max | 02/2020 | 350 |
+----------+---------+--------------------------------------------+
I came this far:
I can group the scores by user like this:
SELECT
username, (max(scoreA) + max(scoreB)) AS combined_score,
FROM score_table
GROUP BY username
ORDER BY combined_score DESC
And I can get the best score per date with PARTITION BY like this:
SELECT *
FROM
(SELECT t.*, row_number() OVER (PARTITION BY date ORDER BY scoreA DESC) rn
FROM score_table t) as tmp
WHERE tmp.rn = 1
ORDER BY date
Is there a proper way to combine these statements and get the result I need? Thank you!
Btw. Don't care about possible ties!
You can combine window functions and aggregation functions like this:
SELECT s.*
FROM (SELECT username, date, (max(scoreA) + max(scoreB)) AS combined_score,
ROW_NUMBER() OVER (PARTITION BY date ORDER BY max(scoreA) + max(scoreB) DESC) as seqnum
FROM score_table
GROUP BY username, date
) s
ORDER BY combined_score DESC;
Note that date needs to be part of the aggregation.

For a given table give out the count for each row Oracle SQL

if i have a table like this:
ID | Name | Payment
----------------------
101 | Victor | 10
103 | Andy | 13
134 | Mai | 2
156 | Chris | 68
179 | Ryan | 43
And I wanna have a query that gives out the following
[Count] | ID | Name | Payment
----------------------
1 | 101 | Victor | 10
2 | 103 | Andy | 13
3 | 134 | Mai | 2
4 | 156 | Chris | 68
5 | 179 | Ryan | 43
So it gives out the number of each row but I don't know how to do it ( am a beginner at SQL). Any tips?
Simply use row_number():
select row_number() over (order by id) as "Count",
t.*
from t
order by "Count";
You should have both order bys to be sure the numbering on the rows is correct and the order of the rows in the result set is correct.
use dense_rank()
select *,dense_rank() over(order by id) from t
or you could use count()
select *,count(*) over(order by id) from t
simple
select rownum, ID , Name, Payment from table

Rank Visits SQL Server 2014

I have a sample table of doctor visits by ID. I'm looking to rank the problems by age, partitioned by ID so I can do some statistic calculations on the 2nd and 3rd visit of the same problem by ID. Please Note: I have a larger dataset so i'm looking for something that will handle that.
So far I have
SELECT
ID, Age, Problem, COUNT(Problem) AS cnt,
RANK() OVER (PARTITION BY id ORDER BY Problem, Age ASC) AS rnk
FROM
#Test1
GROUP BY
ID, Problem, Age
ORDER BY
Age ASC
The code runs but the rank is not properly calculated. Please help.
As I understand, you need partition by ID and Problem:
CREATE TABLE #Test1 (ID int, Problem nvarchar(20), Age int)
INSERT INTO #Test1
VALUES
(1,'Arm',50),
(1,'Arm',52),
(1,'Foot',54),
(1,'Tongue',55),
(1,'Arm',59),
(2,'Toe',60),
(2,'Toe',60),
(2,'Arm',61),
(3,'Tooth',75),
(3,'Tooth',76),
(3,'Knee',78)
SELECT
ID,
Age,
Problem,
COUNT(*) OVER (PARTITION BY ID, Problem, Age) as cnt,
RANK() OVER (PARTITION BY ID, Problem ORDER BY Age) as rnk
FROM #Test1 AS t
ORDER BY t.Age
DROP TABLE #Test1
In this solution you will get the same rank = 1 for data (2,'Toe',60). To enumerate them, replace RANK with ROW_NUMBER
I believe you want row_number() instead of rank():
select
id
, Age
, Problem
, cnt = count(*) over (partition by id, Problem)
, rnk = row_number() over (partition by id, Problem order by Age)
from t
order by id, Age, Problem
test setup: http://rextester.com/DUWG50873
returns:
+----+-----+---------+-----+-----+
| id | Age | Problem | cnt | rnk |
+----+-----+---------+-----+-----+
| 1 | 50 | Arm | 3 | 1 |
| 1 | 52 | Arm | 3 | 2 |
| 1 | 54 | Foot | 1 | 1 |
| 1 | 55 | Tongue | 1 | 1 |
| 1 | 59 | Arm | 3 | 3 |
| 2 | 60 | Toe | 2 | 1 |
| 2 | 60 | Toe | 2 | 2 |
| 2 | 61 | Arm | 1 | 1 |
| 3 | 75 | Tooth | 2 | 1 |
| 3 | 76 | Tooth | 2 | 2 |
| 3 | 78 | Knee | 1 | 1 |
+----+-----+---------+-----+-----+

selecting data with highest field value in a field

I have a table, and I'd like to select rows with the highest value. For example:
----------------
| user | index |
----------------
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
| 3 | 4 |
| 3 | 7 |
| 4 | 1 |
| 5 | 1 |
----------------
Expected result:
----------------
| user | index |
----------------
| 1 | 1 |
| 2 | 2 |
| 3 | 7 |
| 4 | 1 |
| 5 | 1 |
----------------
How may I do so? I assume it can be done by some oracle function I am not aware of?
Thanks in advance :-)
You can use MAX() function for that with grouping user column like this:
SELECT "user"
,MAX("index") AS "index"
FROM Table1
GROUP BY "user"
ORDER BY "user";
Result:
| USER | INDEX |
----------------
| 1 | 1 |
| 2 | 2 |
| 3 | 7 |
| 4 | 1 |
| 5 | 1 |
See this SQLFiddle
if you have more than one column
select user , index
from (
select u.* , row_number() over (partition by user order by index desc) as rnk
from some_table u)
where rnk = 1
user is a reserved word - you should use a different name for the column.
select user,max(index) index from tbl
group by user;
Alternatively, you can use analytic functions:
select user,index, max(index) over (partition by user order by 1 ) highest from YOURTABLE
Note: Try NOT to use words like user, index, date etc.. as your column names, as they are reserved words for Oracle. If you will use, then use them with quotation marks, eg. "index", "date"...