How to use FIND_IN_SET and sum column in my SQL query - sql

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

Related

Finding the profile _id of person with maximum number of booking

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;

Combining COUNT and RANK - PostgreSQL

What I need to select is total number of trips made by every 'id_customer' from table user and their id, dispatch_seconds, and distance for first order. id_customer, customer_id, and order_id are strings.
It should looks like this
+------+--------+------------+--------------------------+------------------+
| id | count | #1order id | #1order dispatch seconds | #1order distance |
+------+--------+------------+--------------------------+------------------+
| 1ar5 | 3 | 4r56 | 1 | 500 |
| 2et7 | 2 | dc1f | 5 | 100 |
+------+--------+------------+--------------------------+------------------+
Cheers!
Original post was edited as during discussion S-man helped me to find exact problem solution. Solution by S-man https://dbfiddle.uk/?rdbms=postgres_10&fiddle=e16aa6008990107e55a26d05b10b02b5
db<>fiddle
SELECT
customer_id,
order_id,
order_timestamp,
dispatch_seconds,
distance
FROM (
SELECT
*,
count(*) over (partition by customer_id), -- A
first_value(order_id) over (partition by customer_id order by order_timestamp) -- B
FROM orders
)s
WHERE order_id = first_value -- C
https://www.postgresql.org/docs/current/static/tutorial-window.html
A window function which gets the total record count per user
B window function which orders all records per user by timestamp and gives the first order_id of the corresponding user. Using first_value instead of min has one benefit: Maybe it could be possible that your order IDs are not really increasing by timestamp (maybe two orders come in simultaneously or your order IDs are not sequential increasing but some sort of hash)
--> both are new columns
C now get all columns where the "first_value" (aka the first order_id by timestamp) equals the order_id of the current row. This gives all rows with the first order by user.
Result:
customer_id count order_id order_timestamp dispatch_seconds distance
----------- ----- -------- ------------------- ---------------- --------
1ar5 3 4r56 2018-08-16 17:24:00 1 500
2et7 2 dc1f 2018-08-15 01:24:00 5 100
Note that in these test data the order "dc1f" of user "2et7" has a smaller timestamp but comes later in the rows. It is not the first occurrence of the user in the table but nevertheless the one with the earliest order. This should demonstrate the case first_value vs. min as described above.
You are on the right track. Just use conditional aggregation:
SELECT o.customer_id, COUNT(*)
MAX(CASE WHEN seqnum = 1 THEN o.order_id END) as first_order_id
FROM (SELECT o.*,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_timestamp ASC) as seqnum
FROM orders o
) o
GROUP BY o.customer_id;
Your JOIN is not necessary for this query.
You can use window function :
select distinct customer_id,
count(*) over (partition by customer_id) as no_of_order
min(order_id) over (partition by customer_id order by order_timestamp) as first_order_id
from orders o;
I think there are many mistakes in your original query, your rank isn't partitioned, the order by clause seems incorrect, you filter out all but one "random" order, then apply the count, the list goes on.
Something like this seems closer to what you seem to want?
SELECT
customer_id,
order_count,
order_id
FROM (
SELECT
a.customer_id,
a.order_count,
a.order_id,
RANK() OVER (PARTITION BY a.order_id, a.customer_id ORDER BY a.order_count DESC) AS rank_id
FROM (
SELECT
customer_id,
order_id,
COUNT(*) AS order_count
FROM
orders
GROUP BY
customer_id,
order_id) a) b
WHERE
b.rank_id = 1;

SQL distinct query over two tables

I would like to find the distinct reviews (by year) for each employee showing only the most recent review (by year)
Employee List Employee Reviews
Number | Employee Name GUID | Number | Year
1234 John x5848 1234 2016
4526 Jim xd565 1234 2015
1123 Pam cr484 1123 2016
Result Needed:
Number | Name | GUID | Year
1234 John x5848 2016
1123 Pam cr484 2016
I can't figure out how to write a SQL query that would return me the above results. Anyone have any experience with a query like this or similar?
You can rank your records by giving row numbers to them:
select
guid, number, year,
row_number() over (partition by number order by year desc) as rn
from employee_reviews;
This gives the newest records (order by year desc) per employee (partition by number) row number 1. Hence:
select emp.number, emp.name, rev.guid, rev.year
from employee amp
join
(
select
guid, number, year,
row_number() over (partition by number order by year desc) as rn
from employee_reviews
) rev on rev.number = emp.number and rev.rn = 1;

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

How to select first 2 rows using group's

I have:
Table1
ID date amt
-------------------
001 21/01/2012 1200
001 25/02/2012 1400
001 24/03/2012 1500
001 21/04/2012 1000
002 21/03/2012 1200
002 01/01/2012 0500
002 08/09/2012 1000
.....
I want to select the first two rows from each group of ID ordered by date DESC from Table1.
Query looks like this:
SELECT TOP 2 DATE, ID, AMT FROM TABLE1 GROUP BY ID, AMT --(NOT WORKING)
Expected output:
ID date amt
-------------------
001 21/01/2012 1200
001 25/02/2012 1400
002 21/03/2012 1200
002 01/01/2012 0500
.....
you can take advantage of using Common table Expression and Window Function
WITH recordList
AS
(
SELECT ID, DATE, Amt,
DENSE_RANK() OVER (PARTITION BY ID ORDER BY DATE ASC) rn
FROM tableName
)
SELECT ID, DATE, Amt
FROM recordList
WHERE rn <= 2
SQLFiddle Demo
based on your desired result above, you are ordering the date by ASCENDING.
Ok, You can either use DENSER_RANK() or ROW_NUMBER() but in my answer, I've used DENSE_RANK() because I'm thinking of the duplicates. Anyway, it's the choice of the OP to use ROW_NUMBER() instead of DENSE_RANK().
TSQL Ranking Functions