Writing a query to find MAX number in Oracle SQL - sql

I am suppose to Write a query that will display the largest number of movies rented by one member and that member's name. Give the output column a meaningful name such as MAXIMUM NUMBER.
This is what I have.
select max(maximum_movies)
from (select count(*)maximum_movies
from mm_member join mm_rental on
mm_rental.member_id = mm_member.member_id
group by first, last);
I got the maximum number but the output should be like this.
First Last Maximum_movies
John Doe 4
But the output is
Maximum_movies
4
Any suggestions?

You could use analytic rank this way. Demo on Fiddle
select memberid,
last,
first,
rental_count
from (
select m.mm_memberid memberid,
m.mm_last last,
m.mm_first first,
count(*) rental_count,
rank() over (order by count(*) desc ) as count_ranking
from mm_member m
inner join mm_rental r on m.mm_memberid=r.mm_memberid
group by m.mm_memberid,
m.mm_last,
m.mm_first
)
where count_ranking=1

Something like this:
WITH CTE_CNT AS (
SELECT first, last, COUNT(*) num
FROM
mm_member
JOIN mm_rental ON mm_rental.member_id = mm_member.member_id
GROUP BY first, last
),
SELECT cnt.first, cnt.last, maxrent.mx
FROM (
SELECT MAX(num) as mx FROM CTE_CNT
) maxrent JOIN CTE_CNT AS cnt ON cnt.num = maxrent.mx
;

use this :
select first,last, maximum_movies
from mm_member join mm_rental on
mm_rental.member_id = mm_member.member_id group by first, last where
maximum_movies = (select max(maximum_movies) from (select count(*)maximum_movies
from mm_member join mm_rental on
mm_rental.member_id = mm_member.member_id group by first, last));

You can do the select in only 1 step. It is not really a MAX you are looking for, just a COUNT of the joined table.
SELECT TOP 1
M.member_id
, M.first
, M.last
, COUNT(R.*) MovieCount
FROM mm_member M
JOIN mm_rental R ON R.member_id = M.member_id
GROUP BY M.member_id, M.first, M.last
ORDER BY MovieCount DESC

Related

JOIN 2 tables ORDER BY SUM value

I have 2 tables: 1st is comment, 2nd is rating
SELECT * FROM comment_table a
INNER JOIN (SELECT comment_id, SUM(rating_value) AS total_rating FROM rating_table GROUP BY comment_id) b
ON a.comment_id = b.comment_id
ORDER BY b.total_rating DESC
I tried the above SQL but doesn't work!
Object is to display a list of comments order by rating points of each comments.
SELECT s.* FROM (
SELECT * FROM comment_table a
INNER JOIN (SELECT comment_id, SUM(rating_value) AS total_rating FROM rating_table GROUP BY comment_id) b
ON a.comment_id = b.comment_id
) AS s
ORDER BY s.total_rating DESC
Nest it inside an another select. It will then output the data in the correct order.

For each country, report the movie genre with the highest average rates

For each country, report the movie genre with the highest average ratings, and I am missing only one step that i cant figure it out.
Here's my current code:
SELECT c.code AS c_CODE, menres.genre AS GENRE, AVG(RATE) as AVERAGE_rate,MAX(RATE) AS MAXIMUM_rate, MIN(RATE) AS MINIMUM_rate from movirates
leftJOIN movgenres ON movgenres.movieid = movratings.movieid
left JOIN users ON users.userid = movrates.userid
left JOIN c ON c.code = users.city
LEFT JOIN menres ON movenres.genreid = menres.code
GROUP BY menres.genre , c.code
order by c.code asc, avg(rate) desc, menres.genre desc ;
You can use the ROW_NUMBER window function to assign a unique rank to each of your rows:
partitioned by country code
ordered by descendent average rating
Once you get this ranking, you may want to select all those rows which have the highest average rating (which are the same having the ranking equal to 1).
WITH cte AS (
SELECT c.code AS COUNTRY_CODE,
mg.genre AS GENRE,
AVG(rating) AS AVERAGE_RATING,
MAX(rating) AS MAXIMUM_RATING,
MIN(RATING) AS MINIMUM_RATING
FROM moviesratings r
INNER JOIN moviesgenres g ON g.movieid = r.movieid
INNER JOIN users u ON u.userid = r.userid
INNER JOIN countries c ON c.code = u.country
LEFT JOIN mGenres mg ON mg.code = g.genreid
GROUP BY mg.genre,
c.code
ORDER BY c.code,
AVG(rating) DESC,
mg.genre DESC;
)
SELECT *
FROM (SELECT *,
ROW_NUMBER() OVER(
PARTITION BY COUNTRY_CODE,
ORDER BY AVERAGE_RATING) AS rn
FROM cte) ranked_averages
WHERE rn = 1
Note: The code inside the common table expression is equivalent to yours. If you're willing to share your input tables, I may even suggest an improved query.
You should use window function in this case by using rank() then select the first rank only.
with mov_rates(c.code, genre, average, max, min)
as.
select c.code c_code,
e.genre genre,
avg (rate) avg
max (rate) max
min (rate) min
from movrates a
LEFT join movge.nres b on a.movieid = b.movieid
LEFT join users c on a.userid = c.user
LEFT join countr.ies d on c.code = d.code
left join mGenres e on b.genreid = e.code
group by d.country_code, e.x
),
rategenre (rank, c_code, genre, avgrate, max, min)
as
(
select rank() over (partition by c.c order by avgrates asc) rank,
country code,
genre,
average_r.ating,
maximum_rating,
minimum_.ating
from movrate \\just practicing on something
)
selec.t 2
from genre
where rank = 5
Reference:
OVER Clause

GROUP BY clause does not return winner in each group ID

I am trying to return the winner player in each group id, however, the group by function doesnt seem to work. Will appreciate your input on this.
SELECT
group_id,
player_id AS winner_id
FROM players AS p
LEFT JOIN (
SELECT
sum(first_score) AS total_first,
first_player
FROM matches
GROUP BY first_player
) AS a
ON p.player_id = a.first_player
LEFT JOIN (
SELECT
sum(second_score) as total_second,
second_player
FROM matches
GROUP BY second_player
) AS b
ON p.player_id = b.second_player
GROUP BY p.group_id
ORDER BY
coalesce(total_first, 0) + coalesce(total_second, 0) DESC,
player_id ASC
in your query no aggregate function so no need group by just use distinct
select distinct group_id, player_id as winner_id
from players as p
left join
(SELECT sum(first_score) as total_first, first_player
from matches
group by first_player) as a
on p.player_id = a.first_player
left join
(SELECT sum(second_score) as total_second, second_player
from matches
group by second_player) as b
on p.player_id = b.second_player
order by coalesce(total_first,0)+coalesce(total_second,0) desc, player_id asc
Assuming you want to have each field in levels of grouping, this may be a solution:
SELECT
group_id,
player_id AS winner_id
FROM players AS p
LEFT JOIN (
SELECT
sum(first_score) AS total_first,
first_player
FROM matches
GROUP BY first_player
) AS a
ON p.player_id = a.first_player
LEFT JOIN (
SELECT
sum(second_score) as total_second,
second_player
FROM matches
GROUP BY second_player
) AS b
ON p.player_id = b.second_player
GROUP BY
p.group_id,
p.player_id
ORDER BY
coalesce(total_first, 0) + coalesce(total_second, 0) DESC,
player_id ASC
When using GROUP BY you must specify sequence of all fields in grouping, so the statement is not ambiguous.
If I understand correctly, you want to sum the first and second score for each player, and then choose the one that has the highest value for the group.
So:
SELECT DISTINCT ON (p.group_id) p.group_id, v.player, SUM(score)
FROM matches m CROSS JOIN LATERAL
(VALUES (first_player, first_score),
(second_player, second_score)
) v(player, score) JOIN
players p
ON p.player_id = v.player
GROUP BY p.group_id, v.player
ORDER BY p.group_id, SUM(score) DESC;
Note that your LEFT JOIN approach is dangerous, because there might be some player, some time, some where, who is never first but always second.

Highest Count with a group

I'm having an absolute brain fade
SELECT p.ProductCategory, f.ProductSubCategory, COUNT(*) AS Cnt
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory
GROUP BY p.ProductCategory, f.ProductSubCategory
ORDER BY 1,3 DESC
This shows me the count for each ProductSubCategory, I would like to see only the highest ProductSubCategory per ProductCategory.
I wish to see (I don't care about the Count value)
There are a couple of different ways to do this. One involves joining the results back to themselves and using the max aggregate. But since you are using SQL Server, you can use ROW_NUMBER to achieve the same result:
with cte as (
select p.productcategory, p.ProductSubCategory, COUNT(*) cnt,
ROW_NUMBER() over (partition by p.productcategory order by count(*) desc) rn
from products p
join sales s on p.ProductSubCategory = s.ProductSubCategory
group by p.productcategory, p.ProductSubCategory
)
select *
from cte
where rn = 1
You already got the answer, Please see the following code to. It may help you.
SELECT p.ProductCategory,
f.ProductSubCategory,
COUNT(*) AS Cnt
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory
JOIN (
SELECT p.ProductCategory,
f.ProductSubCategory,
ROW_NUMBER() OVER ( PARTITION BY p.ProductCategory,
f.ProductSubCategory
ORDER BY COUNT(*) DESC) [Row]
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory) Lu
ON P.ProductCategory = Lu.ProductCategory
AND f.ProductSubCategory = Lu.ProductSubCategory
WHERE Lu.Row = 1
GROUP By p.ProductCategory,
f.ProductSubCategory

SELECT distinct gives wrong count

I've got a problem where my count(*) will return the number of rows before distinct rows are filtered.
This is a simplified version of my query. Note that I'll extract a lot of other data from the tables, so group by won't return the same result, as I'd have to group by maybe 10 columns. The way it works is that m is a map mapping q, c and kl, so there can be several references to q.id. I only want one.
SELECT distinct on (q.id) count(*) over() as full_count
from q, c, kl, m
where c.id = m.chapter_id
and q.id = m.question_id
and q.active = 1
and c.class_id = m.class_id
and kl.id = m.class_id
order by q.id asc
If I run this i get full_count = 11210 while it only returns 9137 rows. If I run it without the distinct on (q.id), distinct on (q.id) is indeed the number of rows.
So it seems that the count function doesn't have access to the filtered rows. How can I solve this? Do I need to rethink my approach?
I'm not entirely sure what exactly you are trying to count, but this might get you started:
select id,
full_count,
id_count
from (
SELECT q.id,
count(*) over() as full_count,
count(*) over (partition by q.id) as id_count,
row_number() over (partition by q.id order by q.id) as rn
from q
join m on q.id = m.question_id
join c on c.id = m.chapter_id and c.class_id = m.class_id
join kl on kl.id = m.class_id
where q.active = 1
) t
where rn = 1
order by q.id asc
If you need the count per id, then the column id_count would be what you need. If you need the overall count, but just on row per id, then the full_count is probably what you want.
(note that I re-wrote your implicit join syntax to use explicit JOINs)
Can you use a subquery:
select qid, count(*) over () as full_count
from (SELECT distinct q.id
from q, c, kl, m
where c.id = m.chapter_id
and q.id = m.question_id
and q.active = 1
and c.class_id = m.class_id
and kl.id = m.class_id
) t
order by q.id asc
But the group by is the right approach. The key word distinct in selectis really just syntactic sugar for doing a group by on all non-aggregate-functioned columns.