Get the position of X user in the ranking - sql

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;

Related

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.

SQL formula for Row number

I'm trying to rank the rows in the following table that looks like this:
| ID | Key | Date | Row|
*****************************
| P175 | 5 | 2017-01| 2 |
| P175 | 5 | 2017-02| 2 |
| P175 | 5 | 2017-03| 2 |
| P175 | 12 | 2017-03| 1 |
| P175 | 12 | 2017-04| 1 |
| P175 | 12 | 2017-05| 1 |
This person has two Keys at once during 2017-03, but I want the formula to put '1' for the rows where Key=12 since it reflects the most recent records.
I want the same formula to also work for the people who don't have overlapping Keys, putting '1' for the most recent records:
| ID | Key | Date | Row|
*****************************
| P170 | 8 | 2017-01| 2 |
| P170 | 8 | 2017-02| 2 |
| P170 | 8 | 2017-03| 2 |
| P170 | 6 | 2017-04| 1 |
| P170 | 6 | 2017-05| 1 |
I've tried variations of ROW_NUMBER() OVER PARTITION BY and DENSE_RANK but cannot figure out the correct formula. Thanks for your help.
First calculate the max date for the key. Then use dense_rank():
select t.*,
dense_rank() over (partition by id order by max_date desc, key) as row
from (select t.*, max(date) over (partition by id, key) as max_date
from t
) t;
If the ranges for each key did not overlap, you could do this with a cumulative count distinct:
select t.*, count(distinct key) over (partition by id order by date desc) as rank
from t;
However, this would not work in the first case. I just find it interesting that this does almost the same thing as the first query.
I guess you are looking for something like this
select personid, mykey, month,
dense_rank() over (partition by personid order by mykey desc) rown
from personkeys
order by month
see the example
http://sqlfiddle.com/#!15/cf751/8

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 |
+----+-----+---------+-----+-----+

Getting distinct values with the highest value in a specific column

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

sql - select row from group based on multiple values

I have a table like:
| ID | Val |
+-------+-----+
| abc-1 | 10 |
| abc-2 | 30 |
| cde-1 | 10 |
| cde-2 | 10 |
| efg-1 | 20 |
| efg-2 | 11 |
and would like to get the result based on the substring(ID, 1, 3) and minimum value and ist must be only the first in case the Val has duplicates
| ID | Val |
+-------+-----+
| abc-1 | 10 |
| cde-1 | 10 |
| efg-2 | 11 |
the problem is that I am stuck, because I cannot use group by substring(id,1,3), ID since it will then have again 2 rows (each for abc-1 and abc-2)
WITH
sorted
AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY substring(id,1,3) ORDER BY val, id) AS sequence_id
FROM
yourTable
)
SELECT
*
FROM
sorted
WHERE
sequence_id = 1
SELECT SUBSTRING(id,1,3),MIN(val) FROM Table1 GROUP BY SUBSTRING(id,1,3);
You were grouping the columns using both SUBSTRING(id,1,3),id instead of just SUBSTRING(id,1,3). It works perfectly fine.Check the same example in this below link.
http://sqlfiddle.com/#!3/fd9fc/1