Finding the profile _id of person with maximum number of booking - sql

I have a table as below. I wanted to find the profile_id with maximum number of Book_ids.
PROFILE_ID BOOK_ID
---------- --------------------
A1 001
A2 002
A3 003
A1 004
A3 005
A1 006
A4 007
A1 008
A2 009
A4 010
A3 011
So, first i need to count how many bookings are done by distinct profile_id and I did it like below
SQL>select profile_id, count(book_id) from book group by pro;
PROFILE_ID COUNT(BOOK_ID)
---------- --------------
A4 2
A3 3
A1 4
A2 2
but i wanted the query to return the profile_id with maximum count of booking. And for that, I used the below query
select profile_id from(select profile_id, count(book_id) no_of from book group by pro) deriv where deriv.no_of=max(deriv.no_of);
But it doesn't return the profile_id with max count of booking. I tried many different queries but it won't work.
Can anyone please help me. I am trying to write a general query but not for this particular table.
Little help would me a lot. Thank you

Try this query, i think you need the order by
select profile_id, count(book_id) as no_of
from book
group by pro
order by no_of desc
limit 1
Update to when you need more than 1 results:
SELECT profile_id,
count(book_id) AS no_of
FROM tbl1
GROUP BY profile_id
HAVING no_of =
(SELECT max(no_of)
FROM
(SELECT profile_id,
count(book_id) AS no_of
FROM tbl1
GROUP BY profile_id) tblAlias1)

In Oracle, you can use fetch first:
select profile_id, count(*)
from book
group by profile_id
order by count(*) desc
fetch first 1 row only;
If you want all profiles when there are duplicates, then one method is:
select profile_id, count(*)
from book
group by profile_id
order by count(*) desc
fetch first 1 row only with ties;
Oracle has supported fetch first since version 12C.
In older versions, you would use window functions:
select profile_id, cnt
from (select profile_id, count(*) as cnt,
rank() over (order by count(*) desc) as seqnum
from book b
group by profile_id
) b
where seqnum = 1;

Related

How to use FIND_IN_SET and sum column in my SQL query

Can anyone help me? I have a table result like this:
id_user
score
type
001
30
play
001
40
play
001
30
redeem
002
20
play
002
30
redeem
I want to sum column score group by id_user base on type 'play' and after that I want show ranking using find_in_set. Like this is the result of the table that I want to display:
id_user
total
rank
001
70
1
002
20
2
Previously I used the rank() function in MySQL version 10.4, but it does not work in MySQL version 15.1. This is my previous query:
SELECT id_user, SUM(score) AS total,
RANK() OVER (ORDER BY total DESC) AS rank
FROM result
WHERE type='play'
GROUP BY id_user
I have made some changes in your query. It's working now. Instead of column alias total SUM(score) needs to be used in order by clause of Rank() function's over(). And since Rank is a reserve word I used rnk instead.
DB-Fiddle:
create table result (id_user varchar(5), score int, type varchar(20));
insert into result values('001',30 ,'play');
insert into result values('001',40 ,'play');
insert into result values('001',30 ,'redeem');
insert into result values('002',20 ,'play');
insert into result values('002',30 ',redeem');
Query:
select id_user, SUM(score) AS total, RANK() OVER (ORDER BY SUM(score) DESC) AS rnk FROM result where type='play' GROUP BY id_user
Output:
id_user
total
rnk
001
70
1
002
20
2
db<>fiddle here
If your MySQL version doesn't support rank() you can use subquery to achieve same result:
Query:
select id_user, SUM(score) AS total,
coalesce((select count(distinct id_user) from result r2
where type='play'
group by id_user
having sum(r2.score)>sum(r.score) ),0)+1 AS rnk
FROM result r where type='play'
GROUP BY id_user
Output:
id_user
total
rnk
001
70
1
002
20
2
db<>fiddle here

Count distinct over partition by

I am trying to do a distinct count of names partitioned over their roles. So, in the example below: I have a table with the names and the person's role.
I would like a role count column that gives the total number of distinct people in that role. For example, the role manager comes up four times but there are only 3 distinct people for that role - Sam comes up again on a different date.
If I remove the date column, it works fine using:
select
a.date,
a.Name,
a.Role,
count(a.Role) over (partition by a.Role) as Role_Count
from table a
group by a.date, a.name, a.role
Including the date column then makes it count the total roles rather than by distinct name (which I know I haven't identified in the partition). Giving 4 managers and 3 analysts.
How do I fix this?
Desired output:
Date
Name
Role
Role_Count
01/01
Sam
Manager
3
02/01
Sam
Manager
3
01/01
John
Manager
3
01/01
Dan
Manager
3
01/01
Bob
Analyst
2
02/01
Bob
Analyst
2
01/01
Mike
Analyst
2
Current output:
Date
Name
Role
Role_Count
01/01
Sam
Manager
4
02/01
Sam
Manager
4
01/01
John
Manager
4
01/01
Dan
Manager
4
01/01
Bob
Analyst
3
02/01
Bob
Analyst
3
01/01
Mike
Analyst
3
Unfortunately, SQL Server (and other databases as well) don't support COUNT(DISTINCT) as a window function. Fortunately, there is a simple trick to work around this -- the sum of DENSE_RANK()s minus one:
select a.Name, a.Role,
(dense_rank() over (partition by a.Role order by a.Name asc) +
dense_rank() over (partition by a.Role order by a.Name desc) -
1
) as distinct_names_in_role
from table a
group by a.name, a.role
Unfortunately, COUNT(DISTINCT is not available as a window aggregate. But we can use a combination of DENSE_RANK and MAX to simulate it:
select
a.Name,
a.Role,
MAX(rnk) OVER (PARTITION BY date, Role) as Role_Count
from (
SELECT *,
DENSE_RANK() OVER (PARTITION BY date, Role ORDER BY Name) AS rnk
FROM table
) a
If Name may have nulls then we need to take that into account:
select
a.Name,
a.Role,
MAX(CASE WHEN Name IS NOT NULL THEN rnk END) OVER (PARTITION BY date, Role) as Role_Count
from (
SELECT *,
DENSE_RANK() OVER (PARTITION BY date, Role, CASE WHEN Name IS NULL THEN 0 ELSE 1 END ORDER BY Name) AS rnk
FROM table
) a

How to query the three best players in Oracle?

I have the following table:
NAME | SCORE
ALICE | 100
BOB | 90
CHARLES| 90
DUKE | 80
EVE | 70
...
My question is the following:
How can I extract with one query the name of the three best players? In my example the query should return four rows (ALICE, BOB, CHARLES and DUKE) because there are two silver medalists (they both have 90 points).
Thank You in advance.
Oracle has the DENSE_RANK analytical function for that exact purpose:
select name, score from (
select name, score, dense_rank() over(order by score desc nulls last) rank
-- ^^^^^^^^^^
-- reject NULL score at the end
from t
) V
where rank < 4
order by rank, name
See http://sqlfiddle.com/#!4/88445/5
How about the following
select *
from table1
where score >=
(select score from (
select score, rownum r from (
select distinct score from table1 order by score desc
) where rownum <= 3
) where r = 3)
order by score desc
See also this SQLFiddle: http://sqlfiddle.com/#!4/23e68/1

Get values and like values in SQL

I have a SQL table that contains the following
ID AccountNumber Name
1 12345 Tony
2 123456 Mike
3 123458 Mike
4 45689 Tom
5 666999 Tim
6 6669997 Lisa
7 44455 Tim
8 78901 Matt
9 789011 Roger
What I need to do is show me all records where the Account Number begin with the same value (indeterminate number). For example. In this table, I'd want to select and display the following:
12345
123456
123458
666999
6669997
78901
789011
As you can see, it shows the each row where the AccountNumber matches or has the same beginning number. I haven't been able to find the proper query and would love any help.
Thanks!
The cases that you mention satisfy that the longer starts with the shorter. Here is a query that will get the shortest match for each account number:
select AccountNumber
from (select a.*, count(*) over (partition by ShortestAN) as numAN
from (select a.*,
(select top 1 a2.AccountNumber
from accounts a2
where a.AccountNumber like a2.AccountNumber + '%'
order by length(a2.AccountNumber) asc
) as ShortestAN
from accounts a
) a
) a
where numAN > 1
order by ShortestAN, AccountNumber;
The subquery finds the shortest account number that matches. The rest is just returning the ones where there is more than one match.
select a1.ID, a1.AccountNumber, a1.Name,
a2.ID, a2.AccountNumber, a2.Name
from Accounts a1
join Accounts a2 on LEN(a1.name) <= LEN(a2.name) and SUBSTRING(a2.name, 1, LEN(a1.name)) = a1.name
where /*are not same rows*/ a1.ID <> a2.ID
Would not an order by work if it were ordering as String?
SELECT AccountNumber, Id, Name
FROM Accounts
ORDER BY CAST(AccountNumber AS NVARCHAR(50))

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
)