Mysql query returns duplicate entry - mysql

SELECT *
FROM ( SELECT a.*, a.id AS id_player,
(SELECT COUNT(id)
FROM `vd7qw_footsal_goals`
WHERE a.id = id_player
AND id_group IN (SELECT id_group
from `vd7qw_footsal_groupofleague`
WHERE id_league = 2)
) AS goals,
team.team_name
FROM `vd7qw_footsal_players` AS a
LEFT JOIN vd7qw_footsal_teams AS team
ON team.id = a.id_team
LEFT JOIN vd7qw_footsal_teamofgroup AS tog
ON tog.id_team = team.id
LEFT JOIN vd7qw_footsal_groups AS g
ON g.id = tog.id_group
WHERE (a.state IN (1))
) AS h
WHERE goals > 0
ORDER BY goals DESC
This is my query when I have 2 or more groups in 1 league and player score a goal in each group, query returns the correct number of goals but duplicates player for example:
John Doe got 3 goals in group 1
and
John Doe got 4 goals in group 2
Query returns:
John Doe got 7 goals
where is my mistake?

Try GROUP BY
SELECT *
FROM ( SELECT a.*, a.id AS id_player, (SELECT COUNT(id)
FROM `vd7qw_footsal_goals`
WHERE a.id = id_player
AND id_group IN (SELECT id_group
from `vd7qw_footsal_groupofleague`
WHERE id_league = 2)) AS goals, team.team_name
FROM `vd7qw_footsal_players` AS a
LEFT JOIN vd7qw_footsal_teams AS team
ON team.id = a.id_team
LEFT JOIN vd7qw_footsal_teamofgroup AS tog
ON tog.id_team = team.id
LEFT JOIN vd7qw_footsal_groups AS g
ON g.id = tog.id_group
WHERE (a.state IN (1))) AS h
WHERE goals > 0
GROUP BY id_group
ORDER BY goals DESC

Related

Rank actors with movies released in India based on their average ratings. Which actor is at the top of the list?

-- Note: The actor should have acted in at least five Indian movies. -- (Hint: You should use the weighted average based on votes. If the ratings clash, then the total number of votes should act as the tie breaker
SELECT n.name as actor_name
, r.total_votes
, COUNT(r.movie_id) as movie_count
, r.avg_rating as actor_avg_rating
, RANK() OVER( PARTITION BY
rm.category = 'actor'
ORDER BY
r.avg_rating DESC
) actor_rank
FROM names as n
JOIN role_mapping as rm
ON n.id = rm.movie_id
JOIN movie as m
ON m.id = rm.movie_id
JOIN ratings as r
ON r.movie_id = m.id
where m.country regexp '^INDIA$'
and m.languages regexp '^HINDI$'
group
by actor_name
having count(rm.movie_id) >= 5;
The output gives no error but no result too.
This would work:
SELECT a.name as actor_name, c.total_votes, COUNT(c.movie_id) as movie_count,c.avg_rating as actor_avg_rating,
RANK() OVER( PARTITION BY
d.category = 'actor'
ORDER BY
c.avg_rating DESC
) actor_rank
FROM names a, movie b, ratings c, role_mapping d
where b.country = 'INDIA'
and b.id = c.movie_id
and b.id= d.movie_id
and a.id = d.name_id
group by actor_name
having count(d.movie_id) >= 5
order by actor_avg_rating desc
;
You had tried joining nameid with movie id which is the mistake
SELECT NAME AS actor_name,
Cast(Sum(total_votes)/Count(movie_id) AS DECIMAL(8,0)) AS total_votes,
Count(movie_id) AS movie_count,
avg_rating AS actor_avg_rating,
Dense_rank() OVER(ORDER BY avg_rating DESC) AS actor_rank
FROM names n INNER JOIN role_mapping r ON n.id=r.name_id
INNER JOIN ratings using (movie_id) INNER JOIN movie m ON m.id=r.movie_id
WHERE country="india" AND category="actor"
GROUP BY actor_name
HAVING Count(movie_id)>=5;
WITH top_actor
AS (SELECT b.NAME
AS
actor_name,
Sum(c.total_votes)
AS
total_votes,
Count(DISTINCT a.movie_id)
AS
movie_count,
Round(Sum(c.avg_rating * c.total_votes) / Sum(c.total_votes), 2)
AS
actor_avg_rating
FROM role_mapping a
INNER JOIN names b
ON a.name_id = b.id
INNER JOIN ratings c
ON a.movie_id = c.movie_id
INNER JOIN movie d
ON a.movie_id = d.id
WHERE a.category = 'actor'
AND d.country LIKE '%India%'
GROUP BY a.name_id,
b.NAME
HAVING Count(DISTINCT a.movie_id) >= 5)
SELECT *,
Rank()
OVER (
ORDER BY actor_avg_rating DESC) AS actor_rank
FROM top_actor;

How to limit the max counts

I want to find for each genre of movie, find the N actors who have played in most movies of the genre
Tables and their columns:
actor(actor_id,name)
role(actor_id,movie_id)
movie(movie_id,title)
movie_has_genre(movie_id,genre_id)
genre(genre_id,genre_name)
With this query I can find the actors who played on the most movies of the same genre.
select t1.genre_name, t1.actor_id, t1.max_value
from
(
select g.genre_name, a.actor_id, count(*) as max_value
from genre g
inner join movie_has_genre mhg on mhg.genre_id = g.genre_id
inner join movie m on mhg.movie_id = m.movie_id
inner join role r on m.movie_id = r.movie_id
inner join actor a on a.actor_id = r.actor_id
group by g.genre_name, a.actor_id
) t1
inner join
(
select genre_name, MAX(max_value) AS max_value
from
(
select g.genre_name, a.actor_id, count(*) as max_value
from genre g
inner join movie_has_genre mhg on mhg.genre_id = g.genre_id
inner join movie m on mhg.movie_id = m.movie_id
inner join role r on m.movie_id = r.movie_id
inner join actor a on a.actor_id = r.actor_id
group by g.genre_name, a.actor_id
) t
GROUP BY genre_name
) t2
ON t1.genre_name = t2.genre_name and t1.max_value = t2.max_value
ORDER BY
t1.max_value desc;
But I want to limit the number of the actors to 1.So how can I do that?
Example:
Results I get:
genre_name | actor_id | max_value
==================================
Thriller | 22591 | 7
Drama | 22591 | 6
Crime | 65536 | 3
Horror | 22591 | 3
Action | 292028 | 3
Action | 378578 | 3
Action | 388698 | 3
Results I want:
genre_name | actor_id | max_value
==================================
Thriller | 22591 | 7
Drama | 22591 | 6
Crime | 65536 | 3
Horror | 22591 | 3
Action | 292028 | 3
If you want just one actor selected randomly just add the following line to your code:
select genre_name, actor_id, max_value
from
(
select g.genre_name, a.actor_id, count(*) as max_value
from genre g
inner join movie_has_genre mhg on mhg.genre_id = g.genre_id
inner join movie m on mhg.movie_id = m.movie_id
inner join role r on m.movie_id = r.movie_id
inner join actor a on a.actor_id = r.actor_id
group by g.genre_name, a.actor_id
) t1
inner join
(
select genre_name, MAX(max_value) AS max_value
from
(
select g.genre_name, a.actor_id, count(*) as max_value
from genre g
inner join movie_has_genre mhg on mhg.genre_id = g.genre_id
inner join movie m on mhg.movie_id = m.movie_id
inner join role r on m.movie_id = r.movie_id
inner join actor a on a.actor_id = r.actor_id
group by g.genre_name, a.actor_id
) t
GROUP BY genre_name
) t2
USING(genre_name,max_value)
GROUP BY genre_name, max_value
ORDER BY max_value desc;
Some of the joins you used are redundant.
SELECT
U.genre_name, U.actor_id, U.actor_genre_count
FROM
(SELECT
A.genre_id, A.genre_name, C.actor_id, count(*) actor_genre_count
FROM genre A
JOIN movie_has_genre B
ON A.genre_id=B.genre_id
JOIN role C
ON C.movie_id=B.movie_id
GROUP BY A.genre_id, A.genre_name, C.actor_id) U
JOIN
(SELECT
S.genre_id, S.genre_name, MAX(S.actor_genre_count) max_actor_genre
FROM
(SELECT
A.genre_id, A.genre_name, C.actor_id, count(*) actor_genre_count
FROM genre A
JOIN movie_has_genre B
ON A.genre_id=B.genre_id
JOIN role C
ON C.movie_id=B.movie_id
GROUP BY A.genre_id, A.genre_name, C.actor_id) S
GROUP BY S.genre_id, S.genre_name) V
ON U.genre_name=V.genre_name AND U.actor_genre_count=V.max_actor_genre;
This solution is adapted from this Stack Overflow answer about limiting results by name. I attempted to do a similar query that should choose the first actor_id and only return it.
SELECT id, CategoryName, image, date_listed, item_id
SELECT t1.genre_name, t1.actor_id, t1.actor_movie_count
FROM
(
SELECT g.genre_name, r.actor_id, COUNT(*) as actor_movie_count
FROM genre g
INNER JOIN movie_has_genre mhg ON mhg.genre_id = g.genre_id
INNER JOIN role r ON m.movie_id = r.movie_id
GROUP BY g.genre_name, r.actor_id
) t1
LEFT JOIN
(
SELECT genre_name, actor_id, MAX(actor_movie_count) AS max_actor_movie_count
FROM
(
SELECT g.genre_name, r.actor_id, COUNT(*) AS actor_movie_count
FROM genre g
INNER JOIN movie_has_genre mhg ON mhg.genre_id = g.genre_id
INNER JOIN role r ON m.movie_id = r.movie_id
GROUP BY g.genre_name, r.actor_id
)
GROUP BY genre_name
) t2
ON t1.genre_name = t2.genre_name AND t1.actor_movie_count = t2.max_actor_movie_count AND (t1.actor_id > t2.actor_id)
WHERE t2.genre_id IS NULL
ORDER BY t1.actor_movie_count DESC
If this still doesn't solve your problem, other similar questions with explanations are described below:
SO answer about returning 1 row per group
SO question about limiting query answer to N results per group
SO question about selecting N items per category
External Article: Finding the max/first of a particular group in SQL
You can use a correlated LIMIT 1 subquery to get the id of the actor who played that genre most.
select g.genre_name, (
select r.actor_id
from movie_has_genre mg
join role r on r.movie_id = mg.movie_id
where mg.genre_id = g.genre_id
group by r.actor_id
order by count(*) desc,
r.actor_id asc -- on tie least actor_id wins
) as actor_id
from genre g
The result would be like:
genre_name | actor_id
======================
Thriller | 22591
Drama | 22591
Crime | 65536
Horror | 22591
Action | 292028
As you see, the count is not included. If you need the count, the simple way would be to return it in the same string column with actor_id
Change the SELECT clause in the subquery to
select concat(r.actor_id, ':', count(*)) as actor_id_count
This wil return the actor_id and the count in a single string column like
genre_name | actor_id_count
===========================
Thriller | 22591:7
You can then parse it (with split, explode or what ever) in your application code.
A solution with CTE (Common Table Expression) and ROW_NUMBER() (window functions) (supported by MySQL 8 and MariaDB 10.2) could be:
with cte as (
select g.genre_name, r.actor_id, count(*) as max_value,
row_number() over (partition by g.genre_name order by count(*) desc, r.actor_id) as rn
from genre g
inner join movie_has_genre mhg on mhg.genre_id = g.genre_id
inner join role r on mhg.movie_id = r.movie_id
group by g.genre_name, r.actor_id
)
select genre_name, actor_id, max_value from cte where rn = 1

MYSQL Count where active across tables

I have three tables:
person
-----------
person_id, active
person_team
-----------
person_id, team_id, active
team
-----------
team_id, active
I'd like to get the count on teams from each person where active is true in each table.
So far I have:
SELECT t.id, t.title, t.created_timestamp, COUNT(p_t.tag_id) AS count
FROM team t
LEFT JOIN
person_team p_t ON p_t.team_id = t.id AND p_t.active = 1
WHERE
t.active = 1
GROUP BY t.id
ORDER BY t.title
This gets the count where team and person - team are active, but doesn't take into account whether person is active. Should I use a sub query or another type of join?
You need to add the person table in a join, and count a column from that table:
SELECT t.id, t.title, t.created_timestamp, COUNT(p.id) AS count
FROM team t
LEFT JOIN
person_team p_t ON p_t.team_id = t.id AND p_t.active = 1
LEFT JOIN
person p ON p_t.person_id = p.id AND p.active = 1
WHERE
t.active = 1
GROUP BY t.id
ORDER BY t.title
You should use a inner join on sub select for get the columns not in group by
select k.id, t.title, t.created_timestamp, k.count from
( SELECT t.id COUNT(p_t.tag_id) AS count
FROM team t
LEFT JOIN
person_team p_t ON p_t.team_id = t.id AND p_t.active = 1
WHERE
t.active = 1
GROUP BY t.id ) k
inner join team t on t.id = k.id

Merge 2 SQL Queries/Tables

I spent so much time googling today but i don't even know which keywords to use. So …
The project is an evaluation of a betting game (Football). I have 2 SQL Queries:
SELECT players.username, players.userid, matchdays.userid, matchdays.points, SUM(points) AS gesamt
FROM players INNER JOIN matchdays ON players.userid = matchdays.userid AND matchdays.season_id=5
GROUP BY players.username
ORDER BY gesamt DESC
And my second query:
SELECT max(matchday) as lastmd, points, players.username from players INNER JOIN matchdays ON players.userid = matchdays.userid WHERE matchdays.season_id=5 AND matchday=
(select max(matchday) from matchdays)group by players.username ORDER BY points DESC
The first one adds up the points of every matchday and shows the sum.
The second shows the points of the last gameday.
My Goal is to merge those 2 queries/tables so that the output is a table like
Rank | Username | Points last gameday | Overall points |
I don't even know where to start or what to look for. Any help would be appreciated ;)
use both query with join....use inner join if each userid have value in 2nd query also.also add userid in 2nd query also for join
SET #rank = 0;
SELECT #rank := rank + 1,
t1.username,
t2.points,
t1.gesamt
FROM (
SELECT players.username, players.userid puserid, matchdays.userid muserid, matchdays.points, SUM(points) AS gesamt
FROM players INNER JOIN matchdays ON players.userid = matchdays.userid AND matchdays.season_id=5
GROUP BY players.username
)t1
INNER JOIN
(
SELECT players.userid, max(matchday) as lastmd, points, players.username
from players INNER JOIN matchdays ON players.userid = matchdays.userid
WHERE matchdays.season_id=5 AND matchday=
(select max(matchday) from matchdays)group by players.username
)t2
ON t1.puserid = t2.userid
ORDER BY t1.gesamt
You can use conditional aggregation, i.e. sum the points only when the day is the last day:
SELECT
p.username,
SUM(case when m.matchday = (select max(matchday) from matchdays) then m.points end)
AS last_day_points,
SUM(m.points) AS total_points
FROM players p
INNER JOIN matchdays m ON p.userid = m.userid AND m.season_id = 5
GROUP BY p.userid
ORDER BY total_points DESC;
Or with a join instead of a non-correlated subquery (MySQL should come to the same execution plan):
SELECT
p.username,
SUM(case when m.matchday = last_day.matchday then m.points end) AS last_day_points,
SUM(m.points) AS total_points
FROM players p
INNER JOIN matchdays m ON p.userid = m.userid AND m.season_id = 5
CROSS JOIN
(
select max(matchday) as matchday
from matchdays
) last_day
GROUP BY p.userid
ORDER BY total_points DESC;

mysql filter by result of sub query

i have this Query :
SELECT a.*, a.id AS id_player, (SELECT COUNT(id) FROM `vd7qw_footsal_goals` WHERE a.id = id_player AND g.id = id_group) AS goals,
team.* FROM `vd7qw_footsal_players` AS a
LEFT JOIN vd7qw_footsal_teams AS team ON team.id= a.id_team
LEFT JOIN vd7qw_footsal_teamofgroup AS tog ON tog.id_team = team.id 4
LEFT JOIN vd7qw_footsal_groups AS g ON g.id = tog.id_group
WHERE g.id IN (SELECT id_group from `vd7qw_footsal_groupofleague` WHERE id_league = 2)
AND (a.state IN (1)) AND goals > 0 ORDER BY goals DESC
and i want to filter its resaults by players that have goals
the above query have error in this part goals > 0 i don't know how to do that can any1 help me ?
Try this:
SELECT * FROM
(SELECT a.*, a.id AS id_player, (SELECT COUNT(id) FROM `vd7qw_footsal_goals` WHERE a.id = id_player AND g.id = id_group) AS goals,
team.* FROM `vd7qw_footsal_players` AS a
LEFT JOIN vd7qw_footsal_teams AS team ON team.id= a.id_team
LEFT JOIN vd7qw_footsal_teamofgroup AS tog ON tog.id_team = team.id 4
LEFT JOIN vd7qw_footsal_groups AS g ON g.id = tog.id_group
WHERE g.id IN (SELECT id_group FROM `vd7qw_footsal_groupofleague` WHERE id_league = 2)
AND (a.state IN (1))) AS A WHERE goals > 0 ORDER BY goals DESC