Finding the most repeated value for each associated attribute - sql

I'm practicing some SQL and I thought about the following problem:
For each pub find the time when more people go.
I have the following tables:
GOESTO
id_person id_pub time
1 1 Daytime
2 2 Night time
3 3 All Day
4 1 Daytime
5 2 Night time
6 1 All Day
7 3 Daytime
8 3 Night time
9 3 Night time
10 1 Night time
PUB
id_pub pub_name cost
1 pub1 123
2 pub2 324
3 pub3 345
What I want to get is something like the following:
pub_name time
I think I should use MAX and COUNT functions, but I'm not quite sure how should I do it. It should work in an Oracle database.
Thank you!

Try this one:
WITH mydata AS (
select id_pub, "TIME", count(*) as cnt
from GOESTO
group by id_pub, "TIME"
)
SELECT m.id_pub, m."TIME", m.cnt
FROM mydata m
JOIN (
SELECT id_pub, max( cnt ) as cnt
FROM mydata
GROUP BY id_pub
) x
ON (m.id_pub = x.id_pub AND m.cnt = x.cnt);
or this one
SELECT id_pub, "TIME"
FROM (
SELECT t.*,
dense_rank() over (partition by id_pub order by cnt desc ) rnk
FROM (
select id_pub, "TIME", count(*) as cnt
from GOESTO
group by id_pub, "TIME"
) t
)
WHERE rnk = 1
To get names instead of id_pub values you need to join the above queries with PUB table
SELECT p.pub_name, q."TIME"
FROM ( one_of_the_above_query )q
JOIN PUB p
ON p.id_pub = q.id_pub

Related

How do i select all columns, plus the result of the sum

I have this select:
"Select * from table" that return:
Id
Value
1
1
1
1
2
10
2
10
My goal is create a sum from each Value group by id like this:
Id
Value
Sum
1
1
2
1
1
2
2
10
20
2
10
20
I Have tried ways like:
SELECT Id,Value, (SELECT SUM(Value) FROM Table V2 WHERE V2.Id= V.Id GROUP BY IDRNC ) FROM Table v;
But the is not grouping by id.
Id
Value
Sum
1
1
1
1
1
1
2
10
10
2
10
10
Aggregation aggregates rows, reducing the number of records in the output. In this case you want to apply the result of a computation to each of your records, task carried out by the corresponding window function.
SELECT table.*, SUM(Value) OVER(PARTITION BY Id) AS sum_
FROM table
Check the demo here.
Your attempt looks correct.
Can you try the below query :
It works for me :
SELECT Id, Value,
(SELECT SUM(Value) FROM Table V2 WHERE V2.Id= V.Id GROUP BY ID) as sum
FROM Table v;
You can do it using inner join to join with selection grouped by id :
select t.*, sum
from _table t
inner join (
select id, sum(Value) as sum
from _table
group by id
) as s on s.id = t.id
You can check it here
Your select is ok if you adjust it just a little:
SELECT Id,Value, (SELECT SUM(Value) FROM Table V2 WHERE V2.Id= V.Id GROUP BY IDRNC ) FROM Table v;
GROUP BY IDRNC is a mistake and should be GROUP BY ID
you should give an alias to a sum column ...
subquery selecting the sum does not have to have self table alias to be compared with outer query that has one (this is not a mistake - works either way)
Test:
WITH
a_table (ID, VALUE) AS
(
Select 1, 1 From Dual Union All
Select 1, 1 From Dual Union All
Select 2, 10 From Dual Union All
Select 2, 10 From Dual
)
SELECT ID, VALUE, (SELECT SUM(VALUE) FROM a_table WHERE ID = v.ID GROUP BY ID) "ID_SUM" FROM a_table v;
ID VALUE ID_SUM
---------- ---------- ----------
1 1 2
1 1 2
2 10 20
2 10 20

SUM and MAX function in SQL with multiple group by clause causes issue

I have the following table:
id
student
period
point
1
1
Q1
0
2
2
Q1
2
3
2
Q2
5
4
2
Q3
0
5
3
Q1
7
6
3
Q1
8
7
3
Q2
3
8
3
Q2
1
9
3
Q3
0
10
3
Q3
0
11
4
Q1
1
12
4
Q3
9
I want to know that in which period which student has the most points in total.
When I execute this query:
SELECT
MAX(SUM(point)) score,
student,
`period`
FROM table1
GROUP BY student, `period`
it gives the following error:
#1111 - Invalid use of group function
When I execute this query:
SELECT
`period`,
student,
MAX(p) score
FROM
(
SELECT
SUM(point) p,
student,
`period`
FROM table1
GROUP BY student, `period`
) t1
GROUP BY `period`
it gives the following result:
period
student
score
Q1
1
15
Q2
1
5
Q3
1
9
The periods and their max points are good, but I always have the first student id.
Expected output:
period
student
score
Q1
3
15
Q2
2
5
Q3
4
9
On top of that. If there is more than one student with the highest points, I want to know all of them.
You could use max window function as the following:
WITH sum_pt AS
(
SELECT student, period,
SUM(point) AS st_period_pt
FROM table1
GROUP BY student, period
),
max_sum as
(
SELECT *,
MAX(st_period_pt) OVER (PARTITION BY period) AS max_pt_sum
FROM sum_pt
)
SELECT student, period, st_period_pt
FROM max_sum
WHERE st_period_pt = max_pt_sum
ORDER BY period
See demo.
Try with window functions:
SUM, to get the total points for each <student, period> pair
ROW_NUMBER, to rank points for each period
Then you can select where ranking = 1 to get your highest points for each period.
WITH students_with_total_points AS (
SELECT *, SUM(point) OVER(PARTITION BY student, period) AS total_points
FROM tab
), ranking_on_periods AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY period ORDER BY total_points DESC) AS rn
FROM students_with_total_points
)
SELECT id, student, period, total_points
FROM ranking_on_period
WHERE rn = 1
You could use left join as follows :
select t1.period, t1.student, t1.score
from (
select student, period, score
from (
select student, period, SUM(point) as score
from table1 s
group by student, period
) as s
group by period, student
) as t1
left join (
select student, period, score
from (
select student, period, SUM(point) as score
from table1 s
group by student, period
) as s
group by period, student
) as t2 on t1.student = t2.student and t1.score < t2.score
where t2.score is null;
This query will list also students and their periods if there scores is 0, you can excludes them by adding where close in t1 and t2 temp tables.

Query to restrict results from left join

I have the following query
select S.id, X.id, 15,15,1 from schema_1.tbl_2638 S
JOIN schema_1.tbl_2634_customid X on S.field_1=x.fullname
That returns the following results, where you can see the first column is duplicated on matches to the 2nd table.
1 1 15 15 1
2 3 15 15 1
2 2 15 15 1
3 5 15 15 1
3 4 15 15 1
I'm trying to get a query that would just give me a single row per 1st ID, and the min value from 2nd ID. So I want a result that would be:
1 1 15 15 1
2 2 15 15 1
3 4 15 15 1
I'm a little rust on my SQL skills, how would I write the query to provide the above result?
From your result you can do,this to achieve your result, for much more compicated structures, you can always take a look at window fucntions
select S.id, MIN(X.id) x_id, 15,15,1 from schema_1.tbl_2638 S
JOIN schema_1.tbl_2634_customid X on S.field_1=x.fullname
GROUP BY 1,3,4,5
window function can be used, need always a outer SELECT
SELECT
s_id,x_idm a,b,c
FROM
(select S.id as s_id, X.id as x_id, 15 a ,15 b,1 c
, ROW_NUMBER() OVER (PARTITION BY S.id ORDER BY X.id ASC) rn
from schema_1.tbl_2638 S
JOIN schema_1.tbl_2634_customid X on S.field_1=x.fullname)
WHERE rn = 1
Or as CTE
WITH CTE as (select S.id as s_id, X.id as x_id, 15 a ,15 b,1 c
, ROW_NUMBER() OVER (PARTITION BY S.id ORDER BY X.id ASC) rn
from schema_1.tbl_2638 S
JOIN schema_1.tbl_2634_customid X on S.field_1=x.fullname)
SELECT s_id,x_id,a,b,c FROM CTE WHERE rn = 1

Return last amount for each element with same ref_id

I have 2 tables, one is credit and other one is creditdetails.
Creditdetails creates new row every day for each of credit.
ID Amount ref_id date
1 2 1 16.03
2 3 1 17.03
3 4 1 18.03
4 1 2 16.03
5 2 2 17.03
6 0 2 18.03
I want to sum up amount of every row with the unique id and last date. So the output should be 4 + 0.
You can use ROW_NUMBER to filter on the latest amount per ref_id.
Then SUM it.
SELECT SUM(q.Amount) AS TotalLatestAmount
FROM
(
SELECT
cd.ref_id,
cd.Amount,
ROW_NUMBER() OVER (PARTITION BY cd.ref_id ORDER BY cd.date DESC) AS rn
FROM Creditdetails cd
) q
WHERE q.rn = 1;
A test on db<>fiddle here
With this query:
select ref_id, max(date) maxdate
from creditdetails
group by ref_id
you get all the last dates for each ref_id, so you can join it to the table creditdetails and sum over amount:
select sum(amount) total
from creditdetails c inner join (
select ref_id, max(date) maxdate
from creditdetails
group by ref_id
) g
on g.ref_id = c.ref_id and g.maxdate = c.date
I think you want something like this,
select sum(amount)
from table
where date = ( select max(date) from table);
with the understanding that your date column doesn't appear to be in a standard format so I can't tell if it needs to be formatted in the query to work properly.

Oracle Nested Grouping

The question is: For each day, list the User ID who has read the most number of messages.
user_id msgID read_date
1 1 10
1 2 10
2 2 10
2 2 23
3 2 23
I believe the date is an outer group and user_id is an inner group, but how to do group nesting in sql? Or somehow avoid this?
This is a task for a Window Function:
select *
from
(
select user_id, read_date, count(*) as cnt,
rank()
over (partition by read_date -- each day
order by count(*) desc) as rnk -- maximum number
from tab
group by user_id, read_date
) dt
where rnk = 1
This might return multiple users for one with the same maximum count, if you want just one (randomly) switch to ROW_NUMBER
select user_id
from
(
select user_id,count(msgID)
from table
group by read_date
)
where rownum <= 1;