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
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
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.
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
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.
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;