Hello i have this query and I need to access de artist_id inside subquery. but don't work.
SELECT g.name, SUM(l.month_start_value), GROUP_CONCAT(l.artist_id), GROUP_CONCAT(l.month_start_value)
FROM genre g
LEFT JOIN genre_artist ga ON g.id = ga.genre_id
LEFT JOIN artist a ON ga.artist_id = a.id
LEFT JOIN (SELECT artist_id,
(SELECT CAST(value as SIGNED)
FROM platform_information_artist
WHERE platform_information_id =
(SELECT id from platform_information WHERE platform = 'spotify' AND information = 'monthly_listeners')
and artist_id = a.id
AND DATE(date) >= DATE(NOW()) - INTERVAL 30 DAY
ORDER BY date ASC
LIMIT 1) as month_start_value
FROM platform_information_artist
GROUP BY platform_information_artist.artist_id) l ON a.id = l.artist_id
GROUP BY g.id
ORDER BY g.id ASC;
The line that's wrong is
and artist_id = a.id
Returns this error: [42S22][1054] Unknown column 'a.id' in 'where clause'
I don't know why I can't access to a.id inside subquery.
There's a number of ways to do this. The least change from your current query is to simply change a couple of references:
SELECT g.name AS genre,
SUM(l.month_start_value) AS SumStartValue,
GROUP_CONCAT(l.artist_id) AS ArtistIDs,
GROUP_CONCAT(l.month_start_value) AS MonthStartValues
FROM genre g
LEFT JOIN genre_artist AS ga
ON g.id = ga.genre_id
LEFT JOIN artist AS a
ON ga.artist_id = a.id
LEFT JOIN
( SELECT pia.artist_id,
( SELECT CAST(pia2.value as SIGNED)
FROM platform_information_artist AS pia2
WHERE pia2.platform_information_id = (SELECT id
FROM platform_information
WHERE platform = 'spotify'
AND information = 'monthly_listeners')
AND pia2.artist_id = pia.artist_id
-- ^^ Updated from `a.id` to `pia.artist_id`
AND DATE(pia2.date) >= DATE(NOW()) - INTERVAL 30 DAY
ORDER BY pia2.date ASC
LIMIT 1
) as month_start_value
FROM platform_information_artist AS pia
GROUP BY pia.artist_id
) l
ON a.id = l.artist_id
GROUP BY g.id
ORDER BY g.id ASC;
This version should work in most versions of MySQL.
If you are using newer versions of MySql though you have a couple more options, which are both more efficient than the above. The first is to use a lateral join:
SELECT g.name AS genre,
SUM(l.month_start_value) AS SumStartValue,
GROUP_CONCAT(a.id) AS ArtistIDs,
GROUP_CONCAT(l.month_start_value) AS MonthStartValues
FROM genre g
LEFT JOIN genre_artist AS ga
ON g.id = ga.genre_id
LEFT JOIN artist AS a
ON ga.artist_id = a.id
LEFT JOIN LATERAL
( SELECT CAST(pia.value as SIGNED) AS month_start_value
FROM platform_information_artist AS pia
INNER JOIN platform_information AS i
ON i.id = pia.platform_information_id
WHERE i.platform = 'spotify'
AND i.information = 'monthly_listeners'
AND pia.artist_id = a.id
AND DATE(pia.date) >= DATE(NOW()) - INTERVAL 30 DAY
ORDER BY pia.date ASC
LIMIT 1
) AS l
ON 1= 1
GROUP BY g.id
ORDER BY g.id ASC;
The other is to use ROW_NUMBER() rather than limit to select one value per artist:
SELECT g.name AS genre,
SUM(l.month_start_value) AS SumStartValue,
GROUP_CONCAT(l.artist_id) AS ArtistIDs,
GROUP_CONCAT(l.month_start_value) AS MonthStartValues
FROM genre g
LEFT JOIN genre_artist AS ga
ON g.id = ga.genre_id
LEFT JOIN artist AS a
ON ga.artist_id = a.id
LEFT JOIN
( SELECT pia.artist_id,
CAST(pia.value as SIGNED) AS month_start_value,
ROW_NUMBER() OVER(PARTITION BY pia.artist_id ORDER BY pia.Date) AS RowNum
FROM platform_information_artist AS pia
INNER JOIN platform_information AS i
ON i.id = pia.platform_information_id
WHERE i.platform = 'spotify'
AND i.information = 'monthly_listeners'
AND DATE(pia.date) >= DATE(NOW()) - INTERVAL 30 DAY
) AS l
ON l.artist_id = a.id
AND l.RowNum = 1
GROUP BY g.id
ORDER BY g.id ASC;
Examples of all 3 on db<>fiddle
Related
SELECT n.name as actress_name , r.total_votes , COUNT(r.movie_id) as movie_count, r.avg_rating as actress_avg_rating,
RANK() OVER(
ORDER BY
COUNT(r.movie_id) DESC
) actress_rank
FROM names as n
INNER JOIN role_mapping as rm
ON n.id = rm.name_id
INNER JOIN movie as m
ON rm.name_id = m.id
INNER JOIN ratings as r
ON m.id = r.movie_id
INNER JOIN genre as g
ON g.movie_id = r.movie_id
WHERE r.avg_rating > 8 AND g.genre = 'Drama' AND rm.category ='actress'
GROUP BY actress_name
LIMIT 3;
Please help me with this! I am also confused if it is the average of 'avg_rating' column for a actress.
First, properly run an aggregate query. MySQL due to the ONLY_FULL_GROUP_BY setting turned off permits non-aggregated columns to be omitted in GROUP BY clause which in proper ANSI SQL should error out unless omitted column(s) is functionally dependent on columns in GROUP BY.
Secondly, calculate needed RANK() partitioned on actress_name using the movie_count aggregate. And in outermost query, subset by calculaetd rank column. With CTEs, you can refactor code by these steps:
WITH agg (
SELECT n.name AS actress_name
, SUM(r.total_votes) AS total_votes -- TURNED AGGREGATE
, AVG(r.avg_rating) AS movie_avg_rating -- TURNED AGGREGATE (RENAMED ALIAS)
, COUNT(r.movie_id) AS movie_count
, RANK() OVER(PARTITION BY n.name -- ADDED PARTITION
ORDER BY COUNT(r.movie_id) DESC) AS actress_rank
FROM names as n
INNER JOIN role_mapping as rm
ON n.id = rm.name_id
INNER JOIN movie as m
ON rm.name_id = m.id
AND rm.category ='actress'
INNER JOIN ratings as r
ON m.id = r.movie_id
AND r.avg_rating > 8
INNER JOIN genre as g
ON g.movie_id = r.movie_id
AND g.genre = 'Drama'
GROUP BY n.name
)
SELECT actress_name
, total_votes
, movie_avg_rating
, movie_count
, actress_rank
FROM agg
WHERE actress_rank <= 3
You just need aggregations , and partitioning within the RANK() analytic function, while removing LIMIT clause such as
SELECT *
FROM
(
SELECT n.name AS actress_name ,
AVG(r.avg_rating) AS actress_avg_rating,
SUM(r.total_votes) AS total_votes,
COUNT(r.movie_id) AS movie_count,
RANK() OVER ( PARTITION BY n.name
ORDER BY COUNT(r.movie_id) DESC) AS actress_rank
FROM names AS n
JOIN role_mapping AS rm
ON n.id = rm.name_id
JOIN movie AS m
ON rm.name_id = m.id
JOIN ratings AS r
ON m.id = r.movie_id
JOIN genre AS g
ON g.movie_id = r.movie_id
WHERE r.avg_rating > 8 AND g.genre = 'Drama' AND rm.category ='actress'
GROUP BY actress_name
) q
WHERE actress_rank <= 3
-- 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;
i have queries like this
SET #curr_date = '2017-03-23';
SELECT
curr_week.mid AS MID,
curr_week.EDC AS Merchant_Name ,
COALESCE(curr_week.amount,0) AS Total_Amount_Curr_Week,
COALESCE(curr_week.total_trx,0) AS Total_Trx_Curr_Week,
COALESCE(curr_week.total_user,0) AS Total_User_Curr_Week,
COALESCE(last_week.amount,0) AS Total_Amount_Last_Week,
COALESCE(last_week.total_trx,0) AS Total_Trx_Last_Week,
COALESCE(last_week.total_user,0) AS Total_User_Last_Week
FROM
(
SELECT a.*, b.total_user
FROM
(
SELECT a1.owner_name AS MID, m.name AS EDC,SUM(t1.amount) AS amount, COUNT(t1.id) AS total_trx
FROM members m
JOIN accounts a1 ON a1.member_id = m.id
JOIN transfers t1 ON a1.id = t1.to_account_id
WHERE DATE(t1.DATE) = (#curr_date - INTERVAL 1 DAY)
GROUP BY a1.owner_name
) AS a
JOIN
(-- get total user
SELECT COUNT(r.ecash_no) AS total_user, r.mid, r.merchant_name
FROM
(
SELECT a.`owner_name` AS ecash_no,
a1.owner_name AS MID,
m.name AS merchant_name
FROM accounts a1
JOIN transfers t1 ON a1.id = t1.to_account_id
JOIN members m ON a1.member_id = m.id
JOIN accounts a ON a.id = t1.from_account_id
WHERE DATE(t1.date) = (#curr_date - INTERVAL 1 DAY)
GROUP BY a.owner_name,m.`name`
) AS r
GROUP BY r.mid
) AS b ON a.mid = b.mid
) AS curr_week
JOIN
(
-- last week
SELECT a.*, b.total_user
FROM
(
SELECT a1.owner_name AS MID, m.name AS EDC,SUM(t1.amount) AS amount, COUNT(t1.id) AS total_trx
FROM members m
JOIN accounts a1 ON a1.member_id = m.id
JOIN transfers t1 ON a1.id = t1.to_account_id
WHERE DATE(t1.DATE) = (#curr_date - INTERVAL 1 DAY) - INTERVAL 1 WEEK
GROUP BY a1.owner_name
) AS a
JOIN
(-- get total user
SELECT COUNT(r.ecash_no) AS total_user, r.mid, r.merchant_name
FROM (
SELECT a.`owner_name` AS ecash_no,
a1.owner_name AS MID,
m.name AS merchant_name
FROM accounts a1
JOIN transfers t1 ON a1.id = t1.to_account_id
JOIN members m ON a1.member_id = m.id
JOIN accounts a ON a.id = t1.from_account_id
WHERE DATE(t1.date) = (#curr_date - INTERVAL 1 DAY) - INTERVAL 1 WEEK
GROUP BY a.owner_name,m.`name`
) AS r
GROUP BY r.mid
) AS b ON a.mid = b.mid
) AS last_week ON curr_week.mid = last_week.mid
how can i retrieve all EDC value from joined queries like that.
because if i use join , it displayed only the same values.
and if i use left join, it follows the value from the left query
is there any way to display everything with join?
You can simulate a full outer join of the two tables using the following:
SELECT COALESCE(a.ColA, b.ColA) AS ColA,
COALESCE(a.ColB, b.ColB) AS ColB
FROM tableA a
LEFT JOIN tableB b ON a.ColA = b.ColA
UNION
SELECT COALESCE(a.ColA, b.ColA) AS ColA,
COALESCE(a.ColB, b.ColB) AS ColB
FROM tableA a
RIGHT JOIN tableB b ON a.ColA = b.ColA;
Note: I've assumed that only ColA is the join column. You can add ColB as a join column as well, or use only ColB as a join column. This really depends on the design of your table, but the general approach I gave should still work.
Output:
Demo here:
Rextester
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
This query I have takes a whooping 45 seconds to execute. I have indexes on all fields that are being search.
SELECT SQL_CALC_FOUND_ROWS g.app_group_id, g.id as g_id, p.`id` as form_id,
a.`user` as activity_user,a.`activity` as app_act ,a.*
FROM grouped g
INNER JOIN
(SELECT max(id) as id, app_group_id FROM grouped GROUP BY app_group_id) g1
ON g1.app_group_id = g.app_group_id AND g.id = g1.id
INNER JOIN form p
on p.id = g.id
INNER JOIN
(SELECT a.id, a.date_time, a.user, a.activity FROM log a) a
ON g.id = a.id
WHERE p.agname like '%blahblah%' and p.`save4later` != 'y'
and a.activity = 'APP Submitted' or a.activity = 'InstaQUOTE'
ORDER BY app_group_id DESC limit 0, 100
In my explain it shows im using Using temporary; Using filesort
Indexes are:
activity table: PRIMARY activity_id INDEX date_time INDEX id INDEX activity INDEX user
form table: PRIMARY id INDEX id_md5 INDEX dateadd INDEX dateu INDEX agent_or_underwriter INDEX
grouped table: UNIQUE id INDEX app_group_id INDEX agent_or_underwriter save4later
Any advice is much appreciated
Thank you very much
To start with, try this one:
SELECT
g.app_group_id,
g.id AS g_id,
p.id AS form_id,
a.user AS activity_user,
a.activity AS app_act,
a.id,
a.date_time
FROM grouped g
INNER JOIN
(SELECT MAX(id) AS id, app_group_id FROM grouped GROUP BY app_group_id) g1
ON g1.app_group_id = g.app_group_id AND g.id = g1.id
INNER JOIN form p
ON p.id = g.id
INNER JOIN log a
ON g.id = a.id
WHERE p.agname LIKE '%blahblah%'
AND p.save4later != 'y'
AND a.activity IN('APP Submitted', 'InstaQUOTE')
LIMIT 0, 100
I removed an unnecessary subquery. Also removed ORDER BY. I guess you could do without sorting, and that must speed the query up a lot.
I also removed SQL_CALC_FOUND_ROWS, because, as I mentioned earlier, it should be faster to issue a separate COUNT(*) query.
Your where clause has an "Or" on the "a.Activity". Without ( ) around both activity, it is going through EVERYTHING, all P, G, G1 aliases. I am guessing that might be your bigger issue.
Additionally, I would ensure you have an index on your "Form" table with the ( Save4Later ) column indexed
I would update the query like this:
SELECT STRAIGHT_JOIN SQL_CALC_FOUND_ROWS
g.app_group_id,
g.id as g_id,
QualifyPages.Form_id,
a.`user` as activity_user,
a.`activity` as app_act,
a.*
FROM
( select p.ID as Form_ID
from FORM p
WHERE p.`save4later` != 'y'
AND p.agname like '%blahblah%' ) QualifyPages
JOIN Grouped g
on QualifyPages.Form_ID = g.ID
INNER JOIN
( SELECT app_group_id,
max(id) as MaxIDPerGroup
FROM
grouped
GROUP BY
app_group_id ) g1
ON g.app_group_id = g1.app_group_id
AND g.id = g1.MaxIDPerGroup
INNER JOIN
( SELECT a.id, a.date_time, a.user, a.activity
FROM log a
WHERE a.activity = 'APP Submitted'
or a.activity = 'InstaQUOTE' ) a
ON g.id = a.id
ORDER BY
g.app_group_id DESC
limit
0, 100