SQL Server select first instance of ranked data - sql

I have a query that creates a result set like this:
Rank Name
1 Fred
1 John
2 Mary
2 Fred
2 Betty
3 John
4 Betty
4 Frank
I need to then select the lowest rank for each name, e.g.:
Rank Name
1 Fred
1 John
2 Mary
2 Betty
4 Frank
Can this be done within TSQL?

SELECT MIN(Rank) AS Rank, Name
FROM TableName
GROUP BY Name

yes
select name, min(rank)
from nameTable
group by name

As Paul + Kevin have pointed out, simple cases of returning a value from an aggregate can be extracted using MIN / MAX etc (just note that RANK is a reserved word)
In a more general / complicated case, e.g. where you need to find the second / Nth highest rank, you can use PARTITIONs with ROW_NUMBER() to do ranking and then filter by the rank.
SELECT [Rank], [Name]
FROM
(
SELECT [RANK], [Name],
ROW_NUMBER() OVER (PARTITION BY [Name] ORDER BY [Rank]) as [RowRank]
FROM [MyTable]
) AS [MyTableReRanked]
WHERE [RowRank] = #N
ORDER BY [Rank];

Related

Getting unique record based on max conditions including null values

I need to get back one record of a player's (Rank A players only) most recent win date (some win dates are null but we need to include them) but picking only the last place of their most recent game session. So basically in that order: get their max win_date (if null, still include them) > from there grab their max place > and from there, pick only their max game_session_id.
Table players:
Badge_No Name Game_Session_ID Place Win_Date Rank
565 Barry 012550 4 6/17/2021 A
565 Barry 003521 2 3/04/2021 A
565 Barry 003521 3 3/04/2021 A
565 Barry 003521 4 3/04/2021 A
565 Barry 003521 5 3/04/2021 A
565 Barry 095945 1 6/17/2021 A
101 Lee 065411 1 A
018 Jess 001561 1 5/23/2020 A
018 Jess 002075 1 5/23/2020 A
209 Linda 026541 2 5/06/2021 A
728 Perry 000940 1 1/23/2021 B
Expected Output:
Badge_No Name Game_Session_ID Place Win_Date Rank
565 Barry 012550 4 6/17/2021 A
101 Lee 065411 1 A
018 Jess 002075 1 5/23/2020 A
209 Linda 026541 2 5/06/2021 A
My (wrong) code:
select distinct badge_no,
name, max(game_session_id) game_session_id,
max(place) place, max(win_date) win_date, rank
from players p
where not exists
(select 'x' from players p2
where p2.badge_no = p.badge_no and p.rank = 'B')
group by badge_no, name, rank
Use ROW_NUMBER with an approriate partition:
WITH cte AS (
SELECT p.*, ROW_NUMBER() OVER (PARTITION BY Badge_No
ORDER BY Win_Date DESC, Place DESC, Game_Session_ID DESC) rn
FROM players p
WHERE "Rank" = 'A'
)
SELECT Badge_No, Name, Game_Session_ID, Place, Win_Date, "Rank"
FROM cte
WHERE rn = 1;
select badge_no, name,
max(game_session_id) keep (dense_rank last
order by win_date nulls first, place) as game_session_id,
max(place) keep (dense_rank last order by win_date nulls first) as place,
max(win_date) as win_date, rank
from players
where rank = 'A'
group by badge_no, name, rank
;
If you are not familiar with the first / last aggregate function (don't worry, you would not be alone!), you may want to take a quick look at the documentation to see what it does.

Finding distinct count of combination of columns values in sql

Currently I have a table this :
Roll no. Names
------------------
1 Sam
1 Sam
2 Sasha
2 Sasha
3 Joe
4 Jack
5 Jack
5 Julie
I want to write a query in which I get count of the combination in another column
Required output
Combination distinct count
-----------------------------
2-Sasha 1
5-Jack 1
5-Julie 1
Basically, you could group by these columns and use a count function:
SELECT rollno, name, COUNT(*)
FROM mytable
GROUP BY rollno, name
You could also concat the two columns:
SELECT CONCAT(rollno, '-', name), COUNT(*)
FROM mytable
GROUP BY CONCAT(rollno, '-', name)

Limit column value repeats to top 2

So I have this query:
SELECT
Search.USER_ID,
Search.SEARCH_TERM,
COUNT(*) AS Search.count
FROM Search
GROUP BY 1,2
ORDER BY 3 DESC
Which returns a response that looks like this:
USER_ID SEARCH_TERM count
bob dog 50
bob cat 45
sally cat 38
john mouse 30
sally turtle 10
sally lion 5
john zebra 3
john leopard 1
And my question is: How would I change the query, so that it only returns the top 2 most-searched-for-terms for any given user? So in the example above, the last row for Sally would be dropped, and the last row for John would also be dropped, leaving a total of 6 rows; 2 for each user, like so:
USER_ID SEARCH_TERM count
bob dog 50
bob cat 45
sally cat 38
john mouse 30
sally turtle 10
john zebra 3
In SQL Server, you can put the original query into a CTE, add the ROW_NUMBER() function. Then in the new main query, just add a WHERE clause to limit by the row number. Your query would look something like this:
;WITH OriginalQuery AS
(
SELECT
s.[User_id]
,s.Search_Term
,COUNT(*) AS 'count'
,ROW_NUMBER() OVER (PARTITION BY s.[USER_ID] ORDER BY COUNT(*) DESC) AS rn
FROM Search s
GROUP BY s.[User_id], s.Search_Term
)
SELECT oq.User_id
,oq.Search_Term
,oq.count
FROM OriginalQuery oq
WHERE rn <= 2
ORDER BY oq.count DESC
EDIT: I specified SQL Server as the dbms I used here, but the above should be ANSI-compliant and work in Snowflake.

Issue with returning distinct records based on single column (Oracle)

If I have the table "members" (shown below), how would I go about getting the record of the first occurrence of a membership_id (Oracle).
Expected results
123 John Doe A P
313 Michael Casey A A
113 Luke Skywalker A P
Table - members
membership_id first_name last_name status type
123 John Doe A P
313 Michael Casey A A
113 Luke Skywalker A P
123 Bob Dole A A
313 Lucas Smith A A
SELECT membership_id,
first_name,
last_name,
status,
type
FROM( SELECT membership_id,
first_name,
last_name,
status,
type,
rank() over (partition by membership_id
order by type desc) rnk
FROM members )
WHERE rnk = 1
will work for your sample data set. If you can have ties-- that is, multiple rows with the same membership_id and the same maximum type-- this query will return all those rows. If you only want to return one of the rows where there is a tie, you would either need to add additional criteria to the order by to ensure that all ties are broken or you would need to use the row_number function rather than rank which will arbitrarily break ties.
Select A.*
FROM Members AS A inner join
(Select membership_id, first(first_name) AS FN, first(last_name) AS LN
From Members
Group by membership_id) AS B
ON A.membership_id=B.membership_id and A.first_name=B.FN and A.last_name=B.LN
Hope that helps!
select *
from members
where rowid in (
select min(rowid)
from members
group by membership_id
)

Retrieve highest value from sql table

How can retrieve that data:
Name Title Profit
Peter CEO 2
Robert A.D 3
Michael Vice 5
Peter CEO 4
Robert Admin 5
Robert CEO 13
Adrin Promotion 8
Michael Vice 21
Peter CEO 3
Robert Admin 15
to get this:
Peter........4
Robert.......15
Michael......21
Adrin........8
I want to get the highest profit value from each name.
If there are multiple equal names always take the highest value.
select name,max(profit) from table group by name
Since this type of request almost always follows with "now can I include the title?" - here is a query that gets the highest profit for each name but can include all the other columns without grouping or applying arbitrary aggregates to those other columns:
;WITH x AS
(
SELECT Name, Title, Profit, rn = ROW_NUMBER()
OVER (PARTITION BY Name ORDER BY Profit DESC)
FROM dbo.table
)
SELECT Name, Title, Profit
FROM x
WHERE rn = 1;