How to do inner join and group data while limiting related entry to 1 for each of the last two months?












0















I would like to get a list of all URLs from one table together with two ratings for each URL in second table. The problem is that one rating should be from current month (if it exists), the other rating should be from last month (also if it exists). Is that possible to achieve with MySQL? Both ratings should for each URL row be grouped into one cell.



Database would be populated with new values once or maybe multiple times per month.



Table structure and sample data:



urls 
id | url
1 | google.com
2 | apple.com
3 | bing.com

ratings
id | rating | url_id | created_at
1 | 10 | 1 | 2018-10-10
2 | 8 | 2 | 2018-10-10
3 | 11 | 1 | 2018-11-10
4 | 5 | 2 | 2018-11-10
5 | 6 | 3 | 2018-11-25


In the end my goal is to show a simple table of URLs and compare their ratings for each month.



url        | previous rating | current rating
google.com | 10 | 11 (rating has increased)
apple.com | 8 | 5 (rating has decreased)
bing.com | - | 6


This is just a beginning of a query, I don't have idea how would I limit 2 ratings for each url as stated above?



SELECT 
urls.id,
urls.url,
ratings.rating

FROM urls

INNER JOIN ratings
ON urls.id = ratings.url_id









share|improve this question


















  • 1





    Hint, join to the ratings twice, INNER JOIN rating ratings_previous ... INNER JOIN rating rating_current...

    – danblack
    Nov 25 '18 at 23:51
















0















I would like to get a list of all URLs from one table together with two ratings for each URL in second table. The problem is that one rating should be from current month (if it exists), the other rating should be from last month (also if it exists). Is that possible to achieve with MySQL? Both ratings should for each URL row be grouped into one cell.



Database would be populated with new values once or maybe multiple times per month.



Table structure and sample data:



urls 
id | url
1 | google.com
2 | apple.com
3 | bing.com

ratings
id | rating | url_id | created_at
1 | 10 | 1 | 2018-10-10
2 | 8 | 2 | 2018-10-10
3 | 11 | 1 | 2018-11-10
4 | 5 | 2 | 2018-11-10
5 | 6 | 3 | 2018-11-25


In the end my goal is to show a simple table of URLs and compare their ratings for each month.



url        | previous rating | current rating
google.com | 10 | 11 (rating has increased)
apple.com | 8 | 5 (rating has decreased)
bing.com | - | 6


This is just a beginning of a query, I don't have idea how would I limit 2 ratings for each url as stated above?



SELECT 
urls.id,
urls.url,
ratings.rating

FROM urls

INNER JOIN ratings
ON urls.id = ratings.url_id









share|improve this question


















  • 1





    Hint, join to the ratings twice, INNER JOIN rating ratings_previous ... INNER JOIN rating rating_current...

    – danblack
    Nov 25 '18 at 23:51














0












0








0








I would like to get a list of all URLs from one table together with two ratings for each URL in second table. The problem is that one rating should be from current month (if it exists), the other rating should be from last month (also if it exists). Is that possible to achieve with MySQL? Both ratings should for each URL row be grouped into one cell.



Database would be populated with new values once or maybe multiple times per month.



Table structure and sample data:



urls 
id | url
1 | google.com
2 | apple.com
3 | bing.com

ratings
id | rating | url_id | created_at
1 | 10 | 1 | 2018-10-10
2 | 8 | 2 | 2018-10-10
3 | 11 | 1 | 2018-11-10
4 | 5 | 2 | 2018-11-10
5 | 6 | 3 | 2018-11-25


In the end my goal is to show a simple table of URLs and compare their ratings for each month.



url        | previous rating | current rating
google.com | 10 | 11 (rating has increased)
apple.com | 8 | 5 (rating has decreased)
bing.com | - | 6


This is just a beginning of a query, I don't have idea how would I limit 2 ratings for each url as stated above?



SELECT 
urls.id,
urls.url,
ratings.rating

FROM urls

INNER JOIN ratings
ON urls.id = ratings.url_id









share|improve this question














I would like to get a list of all URLs from one table together with two ratings for each URL in second table. The problem is that one rating should be from current month (if it exists), the other rating should be from last month (also if it exists). Is that possible to achieve with MySQL? Both ratings should for each URL row be grouped into one cell.



Database would be populated with new values once or maybe multiple times per month.



Table structure and sample data:



urls 
id | url
1 | google.com
2 | apple.com
3 | bing.com

ratings
id | rating | url_id | created_at
1 | 10 | 1 | 2018-10-10
2 | 8 | 2 | 2018-10-10
3 | 11 | 1 | 2018-11-10
4 | 5 | 2 | 2018-11-10
5 | 6 | 3 | 2018-11-25


In the end my goal is to show a simple table of URLs and compare their ratings for each month.



url        | previous rating | current rating
google.com | 10 | 11 (rating has increased)
apple.com | 8 | 5 (rating has decreased)
bing.com | - | 6


This is just a beginning of a query, I don't have idea how would I limit 2 ratings for each url as stated above?



SELECT 
urls.id,
urls.url,
ratings.rating

FROM urls

INNER JOIN ratings
ON urls.id = ratings.url_id






mysql






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 25 '18 at 23:43









Ivan TopićIvan Topić

79931123




79931123








  • 1





    Hint, join to the ratings twice, INNER JOIN rating ratings_previous ... INNER JOIN rating rating_current...

    – danblack
    Nov 25 '18 at 23:51














  • 1





    Hint, join to the ratings twice, INNER JOIN rating ratings_previous ... INNER JOIN rating rating_current...

    – danblack
    Nov 25 '18 at 23:51








1




1





Hint, join to the ratings twice, INNER JOIN rating ratings_previous ... INNER JOIN rating rating_current...

– danblack
Nov 25 '18 at 23:51





Hint, join to the ratings twice, INNER JOIN rating ratings_previous ... INNER JOIN rating rating_current...

– danblack
Nov 25 '18 at 23:51












1 Answer
1






active

oldest

votes


















1














You can use conditional aggregation to get the result you want. I have assumed you would like to use the average rating for each month for comparison purposes.



SELECT u.url, 
AVG(CASE WHEN MONTH(r.created_at) = MONTH(CURDATE() - INTERVAL 1 MONTH)
AND YEAR(r.created_at) = YEAR(CURDATE() - INTERVAL 1 MONTH) THEN rating END) AS `previous rating`,
AVG(CASE WHEN MONTH(r.created_at) = MONTH(CURDATE())
AND YEAR(r.created_at) = YEAR(CURDATE()) THEN rating END) AS `current rating`
FROM urls u
LEFT JOIN ratings r
ON r.url_id = u.id
GROUP BY u.url
ORDER BY `current rating` DESC


Output:



url         previous rating     current rating
google.com 10.0000 11.0000
bing.com 6.0000
apple.com 8.0000 5.0000


Update



To only use the last rating from each month (as requested in comments) is a little more complex. It can be done with two JOINs to tables which contain the last rating for the previous and current months:



SELECT u.url,
pr.rating AS `previous rating`,
cr.rating AS `current rating`
FROM urls u
LEFT JOIN (SELECT url_id, rating
FROM ratings r1
WHERE created_at = (SELECT MAX(created_at)
FROM ratings r2
WHERE r2.url_id = r1.url_id AND
MONTH(created_at) = MONTH(CURDATE() - INTERVAL 1 MONTH) AND
YEAR(created_at) = YEAR(CURDATE() - INTERVAL 1 MONTH)
)
) pr ON pr.url_id = u.id
LEFT JOIN (SELECT url_id, rating
FROM ratings r1
WHERE created_at = (SELECT MAX(created_at)
FROM ratings r2
WHERE r2.url_id = r1.url_id
)
) cr ON cr.url_id = u.id
ORDER BY `current rating` DESC


Updated demo on dbfiddle






share|improve this answer


























  • Thank you very much, I don't need averages, just the single last value from current and last month. Hm how can I remove average? :)

    – Ivan Topić
    Nov 26 '18 at 15:54











  • @IvanTopić see my edit. The second query will give you the last rating for each month rather than the average. The updated demo includes both queries so you can compare results.

    – Nick
    Nov 26 '18 at 21:55











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53473129%2fhow-to-do-inner-join-and-group-data-while-limiting-related-entry-to-1-for-each-o%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














You can use conditional aggregation to get the result you want. I have assumed you would like to use the average rating for each month for comparison purposes.



SELECT u.url, 
AVG(CASE WHEN MONTH(r.created_at) = MONTH(CURDATE() - INTERVAL 1 MONTH)
AND YEAR(r.created_at) = YEAR(CURDATE() - INTERVAL 1 MONTH) THEN rating END) AS `previous rating`,
AVG(CASE WHEN MONTH(r.created_at) = MONTH(CURDATE())
AND YEAR(r.created_at) = YEAR(CURDATE()) THEN rating END) AS `current rating`
FROM urls u
LEFT JOIN ratings r
ON r.url_id = u.id
GROUP BY u.url
ORDER BY `current rating` DESC


Output:



url         previous rating     current rating
google.com 10.0000 11.0000
bing.com 6.0000
apple.com 8.0000 5.0000


Update



To only use the last rating from each month (as requested in comments) is a little more complex. It can be done with two JOINs to tables which contain the last rating for the previous and current months:



SELECT u.url,
pr.rating AS `previous rating`,
cr.rating AS `current rating`
FROM urls u
LEFT JOIN (SELECT url_id, rating
FROM ratings r1
WHERE created_at = (SELECT MAX(created_at)
FROM ratings r2
WHERE r2.url_id = r1.url_id AND
MONTH(created_at) = MONTH(CURDATE() - INTERVAL 1 MONTH) AND
YEAR(created_at) = YEAR(CURDATE() - INTERVAL 1 MONTH)
)
) pr ON pr.url_id = u.id
LEFT JOIN (SELECT url_id, rating
FROM ratings r1
WHERE created_at = (SELECT MAX(created_at)
FROM ratings r2
WHERE r2.url_id = r1.url_id
)
) cr ON cr.url_id = u.id
ORDER BY `current rating` DESC


Updated demo on dbfiddle






share|improve this answer


























  • Thank you very much, I don't need averages, just the single last value from current and last month. Hm how can I remove average? :)

    – Ivan Topić
    Nov 26 '18 at 15:54











  • @IvanTopić see my edit. The second query will give you the last rating for each month rather than the average. The updated demo includes both queries so you can compare results.

    – Nick
    Nov 26 '18 at 21:55
















1














You can use conditional aggregation to get the result you want. I have assumed you would like to use the average rating for each month for comparison purposes.



SELECT u.url, 
AVG(CASE WHEN MONTH(r.created_at) = MONTH(CURDATE() - INTERVAL 1 MONTH)
AND YEAR(r.created_at) = YEAR(CURDATE() - INTERVAL 1 MONTH) THEN rating END) AS `previous rating`,
AVG(CASE WHEN MONTH(r.created_at) = MONTH(CURDATE())
AND YEAR(r.created_at) = YEAR(CURDATE()) THEN rating END) AS `current rating`
FROM urls u
LEFT JOIN ratings r
ON r.url_id = u.id
GROUP BY u.url
ORDER BY `current rating` DESC


Output:



url         previous rating     current rating
google.com 10.0000 11.0000
bing.com 6.0000
apple.com 8.0000 5.0000


Update



To only use the last rating from each month (as requested in comments) is a little more complex. It can be done with two JOINs to tables which contain the last rating for the previous and current months:



SELECT u.url,
pr.rating AS `previous rating`,
cr.rating AS `current rating`
FROM urls u
LEFT JOIN (SELECT url_id, rating
FROM ratings r1
WHERE created_at = (SELECT MAX(created_at)
FROM ratings r2
WHERE r2.url_id = r1.url_id AND
MONTH(created_at) = MONTH(CURDATE() - INTERVAL 1 MONTH) AND
YEAR(created_at) = YEAR(CURDATE() - INTERVAL 1 MONTH)
)
) pr ON pr.url_id = u.id
LEFT JOIN (SELECT url_id, rating
FROM ratings r1
WHERE created_at = (SELECT MAX(created_at)
FROM ratings r2
WHERE r2.url_id = r1.url_id
)
) cr ON cr.url_id = u.id
ORDER BY `current rating` DESC


Updated demo on dbfiddle






share|improve this answer


























  • Thank you very much, I don't need averages, just the single last value from current and last month. Hm how can I remove average? :)

    – Ivan Topić
    Nov 26 '18 at 15:54











  • @IvanTopić see my edit. The second query will give you the last rating for each month rather than the average. The updated demo includes both queries so you can compare results.

    – Nick
    Nov 26 '18 at 21:55














1












1








1







You can use conditional aggregation to get the result you want. I have assumed you would like to use the average rating for each month for comparison purposes.



SELECT u.url, 
AVG(CASE WHEN MONTH(r.created_at) = MONTH(CURDATE() - INTERVAL 1 MONTH)
AND YEAR(r.created_at) = YEAR(CURDATE() - INTERVAL 1 MONTH) THEN rating END) AS `previous rating`,
AVG(CASE WHEN MONTH(r.created_at) = MONTH(CURDATE())
AND YEAR(r.created_at) = YEAR(CURDATE()) THEN rating END) AS `current rating`
FROM urls u
LEFT JOIN ratings r
ON r.url_id = u.id
GROUP BY u.url
ORDER BY `current rating` DESC


Output:



url         previous rating     current rating
google.com 10.0000 11.0000
bing.com 6.0000
apple.com 8.0000 5.0000


Update



To only use the last rating from each month (as requested in comments) is a little more complex. It can be done with two JOINs to tables which contain the last rating for the previous and current months:



SELECT u.url,
pr.rating AS `previous rating`,
cr.rating AS `current rating`
FROM urls u
LEFT JOIN (SELECT url_id, rating
FROM ratings r1
WHERE created_at = (SELECT MAX(created_at)
FROM ratings r2
WHERE r2.url_id = r1.url_id AND
MONTH(created_at) = MONTH(CURDATE() - INTERVAL 1 MONTH) AND
YEAR(created_at) = YEAR(CURDATE() - INTERVAL 1 MONTH)
)
) pr ON pr.url_id = u.id
LEFT JOIN (SELECT url_id, rating
FROM ratings r1
WHERE created_at = (SELECT MAX(created_at)
FROM ratings r2
WHERE r2.url_id = r1.url_id
)
) cr ON cr.url_id = u.id
ORDER BY `current rating` DESC


Updated demo on dbfiddle






share|improve this answer















You can use conditional aggregation to get the result you want. I have assumed you would like to use the average rating for each month for comparison purposes.



SELECT u.url, 
AVG(CASE WHEN MONTH(r.created_at) = MONTH(CURDATE() - INTERVAL 1 MONTH)
AND YEAR(r.created_at) = YEAR(CURDATE() - INTERVAL 1 MONTH) THEN rating END) AS `previous rating`,
AVG(CASE WHEN MONTH(r.created_at) = MONTH(CURDATE())
AND YEAR(r.created_at) = YEAR(CURDATE()) THEN rating END) AS `current rating`
FROM urls u
LEFT JOIN ratings r
ON r.url_id = u.id
GROUP BY u.url
ORDER BY `current rating` DESC


Output:



url         previous rating     current rating
google.com 10.0000 11.0000
bing.com 6.0000
apple.com 8.0000 5.0000


Update



To only use the last rating from each month (as requested in comments) is a little more complex. It can be done with two JOINs to tables which contain the last rating for the previous and current months:



SELECT u.url,
pr.rating AS `previous rating`,
cr.rating AS `current rating`
FROM urls u
LEFT JOIN (SELECT url_id, rating
FROM ratings r1
WHERE created_at = (SELECT MAX(created_at)
FROM ratings r2
WHERE r2.url_id = r1.url_id AND
MONTH(created_at) = MONTH(CURDATE() - INTERVAL 1 MONTH) AND
YEAR(created_at) = YEAR(CURDATE() - INTERVAL 1 MONTH)
)
) pr ON pr.url_id = u.id
LEFT JOIN (SELECT url_id, rating
FROM ratings r1
WHERE created_at = (SELECT MAX(created_at)
FROM ratings r2
WHERE r2.url_id = r1.url_id
)
) cr ON cr.url_id = u.id
ORDER BY `current rating` DESC


Updated demo on dbfiddle







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 26 '18 at 21:54

























answered Nov 26 '18 at 0:09









NickNick

28k121941




28k121941













  • Thank you very much, I don't need averages, just the single last value from current and last month. Hm how can I remove average? :)

    – Ivan Topić
    Nov 26 '18 at 15:54











  • @IvanTopić see my edit. The second query will give you the last rating for each month rather than the average. The updated demo includes both queries so you can compare results.

    – Nick
    Nov 26 '18 at 21:55



















  • Thank you very much, I don't need averages, just the single last value from current and last month. Hm how can I remove average? :)

    – Ivan Topić
    Nov 26 '18 at 15:54











  • @IvanTopić see my edit. The second query will give you the last rating for each month rather than the average. The updated demo includes both queries so you can compare results.

    – Nick
    Nov 26 '18 at 21:55

















Thank you very much, I don't need averages, just the single last value from current and last month. Hm how can I remove average? :)

– Ivan Topić
Nov 26 '18 at 15:54





Thank you very much, I don't need averages, just the single last value from current and last month. Hm how can I remove average? :)

– Ivan Topić
Nov 26 '18 at 15:54













@IvanTopić see my edit. The second query will give you the last rating for each month rather than the average. The updated demo includes both queries so you can compare results.

– Nick
Nov 26 '18 at 21:55





@IvanTopić see my edit. The second query will give you the last rating for each month rather than the average. The updated demo includes both queries so you can compare results.

– Nick
Nov 26 '18 at 21:55


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53473129%2fhow-to-do-inner-join-and-group-data-while-limiting-related-entry-to-1-for-each-o%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

Calculate evaluation metrics using cross_val_predict sklearn

Insert data from modal to MySQL (multiple modal on website)