count most occurences with the WHERE from other table - mysql

I have a movie DB to organize my collection but also I'm using it to learn more of mySQL. along the development I find bumps (plenty of them) and right now my problem is this:
Table ACTORS:
id_actor
name
sex
Table MOVIEACTORES:
id_movieactores
id_movie
id_actor
I want to count the TOP 5 (top10, top20 or whatever!) of actors with most movies and then the Top5 of actresses with most movies!
I have this:
SELECT filmesactores.id_actor,
COUNT( * ) AS contagem
FROM filmesactores
GROUP BY id_actor
ORDER BY contagem DESC
LIMIT 10
But this code doesn't discriminates actors from actresses. I feel the solution might be simple but with my knowledge is out of my reach right now. Anyone?

Grouping by sex, name would separate actors' counts by gender, but since you want to apply the limit to each gender group (i.e. top 5 actors and top 5 actresses), perform two queries and UNION their results together:
SELECT name, COUNT(*) AS moviecount
FROM actors
JOIN movieactores ON actors.id_actor = movieactores.id_actor
WHERE sex = 'Male'
GROUP BY name
ORDER BY COUNT(id_movie) DESC
LIMIT 5
UNION
SELECT name, COUNT(*)
FROM actors
JOIN movieactores ON actors.id_actor = movieactores.id_actor
WHERE sex = 'Female'
GROUP BY name
ORDER BY COUNT(id_movie) DESC
LIMIT 5

Related

How to do multiple tasks in a single SQL query

I was given the database below:
movie(movie_id, movie_name, production_year, votes, ranking, rating)
movie_info(movie_id, movie_genre_id, note)
movie_genre(movie_genre_id, genre_name)
person(person_id, person_name, gender)
role(person_id, movie_id, role_name, role_type_id)
role_type(role_type_id, type_name)
I was asked to display the name of the top 7 directors with at least 3 movies in the list, the number of movies they are in and the average rating of their movies, sorted by the average rating. With the query below I managed to get the name of the directors, the number of movies they are in and the average rating, but I'm having issues limiting it to the top 7 and sorting them by the average rating. I tried using LIMIT and ORDER BY, but I'm getting syntax errors.
SELECT
person_name, COUNT(role.movie_id), AVG(rating)
FROM
movie
INNER JOIN
role
ON role.movie_id = movie.movie_id
INNER JOIN
person
ON role.person_id = person.person_id
INNER JOIN
role_type
ON role.role_type_id = role_type.role_type_id
WHERE
type_name = 'director'
GROUP BY
person_name
HAVING
COUNT(role.movie_id) > 2;
I can even order by the number of movies they did and limit it to the top 7, but for God I cannot order it by the AVG(rating)
person_name COUNT(role.movie_id) AVG(rating)
Hitchcock, Alfred 9 8.2888890372382
Kubrick, Stanley 8 8.2999999523163
Wilder, Billy 6 8.3000000317891
Spielberg, Steven 6 8.4000000953674
Scorsese, Martin 6 8.3166666030884
Nolan, Christopher 6 8.5333331425985
Tarantino, Quentin 6 8.3666666348775
In MySQL, Aliases defined in the Select clauses can be used in the Group By, Order By and Having clauses.
Use Order by .. DESC to sort the result-set in descending order and Limit 7 to get only 7 rows.
You should use proper Aliasing in multi table queries, to avoid ambiguous and unintended behavior.
You need to use Group By on person_id also, as there may be cases where director(s) have same name.
If you have duplicate entries in role table, you will have to use Count(Distinct ...) to avoid counting duplicate rows.
Try the following query:
SELECT
p.person_id,
p.person_name,
COUNT(r.movie_id) AS movies_count,
AVG(m.rating) AS average_rating
FROM
movie AS m
INNER JOIN
role AS r
ON r.movie_id = m.movie_id
INNER JOIN
person AS p
ON r.person_id = p.person_id
INNER JOIN
role_type AS rt
ON r.role_type_id = rt.role_type_id
WHERE
rt.type_name = 'director'
GROUP BY
p.person_id,
p.person_name
HAVING
movies_count > 2
ORDER BY
movies_count DESC,
average_rating DESC
LIMIT 7

How to have three counts in one sql query and will display 3 separated results in mySQL?

I have two tables. My first table is animal_tbl the second one is animal_ate_tbl and food_type_tbl.
this is the visualization of animal_tbl:
animal_ate_tbl:
food_type_tbl
I want a query that will select the: animal_num, animal_fname+animal_lname, count of banana she ate and count of apple she ate and the count of chico she ate. I created my own query however it is outputing the wrong result. can you help me? I promise to vote up the one who can help me :))
this is the sample query i got but is wrong:
select
a.animal_num,
a.animal_fname,
a.animal_lname,
(
SELECT
COUNT(*)
FROM
animal_ate_tbl
WHERE
food_id = x22
group by
animal_id
) as banana,
(
SELECT
COUNT(*)
FROM
animal_ate_tbl
WHERE
food_id = x33
group by
animal_id
) as banana,
(
SELECT
COUNT(*)
FROM
animal_ate_tbl
WHERE
food_id = x44
group by
animal_id
) as chico
from
animal_tbl as a,
animal_ate_tbl
group by
a.animal_num = animal_id
However, this should be the output:
I will promise that i will give an upvote to those who will answer. btw the table is only a sample table that im doing.
Try this instead:
SELECT
A.animal_num,
CONCAT(IFNULL(A.animal_fname,''),' ', IFNULL(A.animal_lname,'')) fullName,
(SUM(IF(C.food_type='banana',1,0))) banana,
(SUM(IF(C.food_type='apple',1,0))) apple,
(SUM(IF(C.food_type='chico',1,0))) chico
FROM animal_tbl A LEFT JOIN animal_ate_tbl B
ON A.animal_nu=B.animal_id LEFT JOIN food_type_tbl C
ON B.food_id=C.food_id
GROUP BY A.animal_num,
CONCAT(IFNULL(A.animal_fname,''),' ', IFNULL(A.animal_lname,''));

mySQL IF condition THEN condition

I am struggling with the WHERE part of a query. The query itself contains a LEFT JOIN based on an ID that is present in both tables. However I require the where statement to only return the largest single result that is present in one of the columns. Currently I am return all the values in the join, including values that I do not want.
My Current SQL is
SELECT u.uid, t.id
GROUP_CONCAT(u.forename, ' ', u.surname) AS name,
GROUP CONCAT(DISTINCT scores.points) AS point
FROM users AS U
JOIN teamname AS t
LEFT JOIN (
SELECT team_id, id
FROM games AS g
LEFT JOIN (
SELECT points, team_id
FROM scores as s
) AS S ON t.id = S.team_id
WHERE IF (S.points > 3, S.points > 2, S.point =1)
) AS G ON t.id = G.team_id
ORDER BY surname ASC;
The result of such might be something along the lines of
NAME | TEAM | GAMES | POINTS
Joe | 1 | 1,2,3,4 | 1,3,3,2,3
In this instance the first game was a draw and was replied resulting in a higher points score, I am only wanting the higher points score based on that game.
Any help would be appreciated.
Updated with Tables
users
uid
forename
surname
Team
id
teamname
uid
games
id
team_id
points
Still not quite sure if I understood your tables correctly. It seems a users has one or more teams, each team has one or more games with one or more results per game. You want to show for each user and each team the games concatenated in one column and the highest points for each game concatenated in a second column.
If my assumptions are correct the following query should do the trick. Basically, you first group the data by user/team/game and select the max points per game, then you group the results by user/team and concatenate the games and points.
Please let me know if I misunderstood any of your requirements.
Example in an SQL Fiddle
SELECT
t.uid,
t.forename,
t.team_id,
GROUP_CONCAT(t.game_id) as games,
GROUP_CONCAT(t.max_points) as max_points
FROM (
SELECT
users.uid,
users.forename,
teams.id AS team_id,
games.id AS game_id,
max(games.points) as max_points
FROM
users
LEFT JOIN teams ON users.uid = teams.uid
LEFT JOIN games ON teams.id = games.team_id
GROUP BY
users.uid,
users.forename,
teams.id,
games.id
) t
GROUP BY
t.uid,
t.forename,
t.team_id

Find the frequency of rows from multiple joint tables

I have this problem with SQL and I can't figure it out.
Imagine that I have 3 tables as follows
Names
Nameid name
1 Starbucks Coffee
2 Johns Restaurant
3 Davids Restaurant
user_likes
userid Nameid
1 1
2 1
2 3
user_visited
userid Nameid
1 2
I want to find the places with the most number of (likes+visited). I also want to select all places not just those who have been liked or visited
I do:
SELECT n.nameid, n.name , COUNT(f.nameid) AS freq
FROM names AS n
LEFT JOIN user_likes ON n.nameid=user_likes.nameid
LEFT JOIN user_visited ON n.nameid=user_visited.nameid
ORDER BY freq DESC
But it doesn't give me the total frequency. The problem is, if a place is both visited and liked, it is counted only once, while I want it to be counted twice.
Any suggestions?
I've made a quick test and although I prefer Serge's solution, this one seemed to perform faster as the amount of items to join will be less:
SELECT n.nameId, n.name, coalesce(sum(likesCount), 0) totalCount FROM NAMES n
LEFT JOIN (
SELECT nameId, count(*) likesCount FROM user_likes
GROUP BY nameId
UNION ALL
SELECT nameId, count(*) visitsCount FROM user_visited
GROUP BY nameId
) s ON n.nameId = s.nameId
GROUP BY n.nameId
ORDER BY totalCount DESC
I'm assuming the following indexes:
alter table names add index(nameid);
alter table user_likes add index(nameid);
alter table user_visited add index(nameid);
Probably the OP can compare the efficiency of both queries with actual data and provide feedback.
SELECT n.name, t.nameid, COUNT(t.nameid) AS freq
FROM Names n
JOIN (
SELECT nameid FROM user_likes
UNION ALL
SELECT nameid FROM user_visited
) t
ON n.nameid = t.nameid
GROUP BY t.nameid ORDER BY freq DESC
Mosty, your usage of coalesce() gave me an idea and I came up with this:
SELECT n.nameid, n.name ,
SUM((IFNULL(user_likes.userid,0)>0)+(IFNULL(user_visited.userid,0)>0) ) AS freq
FROM names AS n LEFT JOIN user_likes ON n.nameid=user_likes.nameid LEFT JOIN
user_visited ON n.nameid=user_visited.nameid ORDER BY freq DESC
Since my example here was a simplification of my problem (I have to join more than two tables to the main table) I'm reluctant to use SELECT inside SELECT, because I know it's not very efficient. Do you see any fundamental problem with my solution?

MySQL query the largest amount present in a collection

I have a table Teacher that contains a TeacherPIN as well as a table Student that contains a TeacherPIN referencing a Teacher. The idea is that a Teacher contains a certain amount of Students.
I am tasked with finding the teacher with the most students. I am currently using the query:
select t.TeacherPIN, count(s.TeacherPIN)
from Teacher t, Student s
where t.TeacherPIN = s.TeacherPIN
and ((select count(s1.TeacherPIN) from Student s1 where s1.TeacherPIN = t.TeacherPIN) >=
(select count(s2.TeacherPIN) from Student s2 where s2.TeacherPIN = (select t1.TeacherPIN from Teacher t1)));
I'm sure I'm making this way more complicated than I should be, but I've been at it for a while now and am hoping someone could push me in the right direction.
Thanks!
To find just one teacher (of possibly many) with maximum number of students:
SELECT TeacherPIN
, COUNT(*) AS NumberOfStudents
FROM Student
GROUP BY TeacherPIN
ORDER BY NumberOfStudents DESC
LIMIT 1
To find all of them:
SELECT TeacherPIN
, COUNT(*) AS NumberOfStudents
FROM Student
GROUP BY TeacherPIN
HAVING COUNT(*) =
( SELECT COUNT(*) AS NumberOfStudents
FROM Student
GROUP BY TeacherPIN
ORDER BY NumberOfStudents DESC
LIMIT 1
)