MySQL - Limit Field To 5 Maximum Occurrences
Background:
I run a platform which allows users to follow creators and view their content.
The following query successfully displays 50 posts ordered by popularity. There is also some other logic to not show posts the user has already saved/removed, but that is not relevant for this question.
Problem:
If one creator is particularly popular (high popularity
), the top 50 posts returned will nearly all be by that creator.
This skews the results as ideally the 50 posts returned will not be in favor of one particular author.
Question:
How can I limit it so the author (which uses the field posted_by
) is returned no more than 5 times. It could be less, but definitely no more than 5 times should one particular author be returned.
It should still be finally ordered by popularity
DESC
SELECT *
FROM `source_posts`
WHERE `posted_by` IN (SELECT `username`
FROM `source_accounts`
WHERE `id` IN (SELECT `sourceid`
FROM `user_source_accounts`
WHERE `profileid` = '100'))
AND `id` NOT IN (SELECT `postid`
FROM `user_posts_removed`
WHERE `profileid` = '100')
AND `live` = '1'
AND `added` >= Date_sub(Now(), INTERVAL 1 month)
AND `popularity` > 1
ORDER BY `popularity` DESC
LIMIT 50
Thank you.
Edit:
I am using MySQL version 5.7.24, so unfortunately the row_number() function will not work in this instance.
mysql sql
add a comment |
Background:
I run a platform which allows users to follow creators and view their content.
The following query successfully displays 50 posts ordered by popularity. There is also some other logic to not show posts the user has already saved/removed, but that is not relevant for this question.
Problem:
If one creator is particularly popular (high popularity
), the top 50 posts returned will nearly all be by that creator.
This skews the results as ideally the 50 posts returned will not be in favor of one particular author.
Question:
How can I limit it so the author (which uses the field posted_by
) is returned no more than 5 times. It could be less, but definitely no more than 5 times should one particular author be returned.
It should still be finally ordered by popularity
DESC
SELECT *
FROM `source_posts`
WHERE `posted_by` IN (SELECT `username`
FROM `source_accounts`
WHERE `id` IN (SELECT `sourceid`
FROM `user_source_accounts`
WHERE `profileid` = '100'))
AND `id` NOT IN (SELECT `postid`
FROM `user_posts_removed`
WHERE `profileid` = '100')
AND `live` = '1'
AND `added` >= Date_sub(Now(), INTERVAL 1 month)
AND `popularity` > 1
ORDER BY `popularity` DESC
LIMIT 50
Thank you.
Edit:
I am using MySQL version 5.7.24, so unfortunately the row_number() function will not work in this instance.
mysql sql
1
What is the MySQL server version ? Also, there is just too manyIN(..
based subqueries. This will not scale well when data gets bigger.
– Madhur Bhaiya
Nov 20 at 18:59
add a comment |
Background:
I run a platform which allows users to follow creators and view their content.
The following query successfully displays 50 posts ordered by popularity. There is also some other logic to not show posts the user has already saved/removed, but that is not relevant for this question.
Problem:
If one creator is particularly popular (high popularity
), the top 50 posts returned will nearly all be by that creator.
This skews the results as ideally the 50 posts returned will not be in favor of one particular author.
Question:
How can I limit it so the author (which uses the field posted_by
) is returned no more than 5 times. It could be less, but definitely no more than 5 times should one particular author be returned.
It should still be finally ordered by popularity
DESC
SELECT *
FROM `source_posts`
WHERE `posted_by` IN (SELECT `username`
FROM `source_accounts`
WHERE `id` IN (SELECT `sourceid`
FROM `user_source_accounts`
WHERE `profileid` = '100'))
AND `id` NOT IN (SELECT `postid`
FROM `user_posts_removed`
WHERE `profileid` = '100')
AND `live` = '1'
AND `added` >= Date_sub(Now(), INTERVAL 1 month)
AND `popularity` > 1
ORDER BY `popularity` DESC
LIMIT 50
Thank you.
Edit:
I am using MySQL version 5.7.24, so unfortunately the row_number() function will not work in this instance.
mysql sql
Background:
I run a platform which allows users to follow creators and view their content.
The following query successfully displays 50 posts ordered by popularity. There is also some other logic to not show posts the user has already saved/removed, but that is not relevant for this question.
Problem:
If one creator is particularly popular (high popularity
), the top 50 posts returned will nearly all be by that creator.
This skews the results as ideally the 50 posts returned will not be in favor of one particular author.
Question:
How can I limit it so the author (which uses the field posted_by
) is returned no more than 5 times. It could be less, but definitely no more than 5 times should one particular author be returned.
It should still be finally ordered by popularity
DESC
SELECT *
FROM `source_posts`
WHERE `posted_by` IN (SELECT `username`
FROM `source_accounts`
WHERE `id` IN (SELECT `sourceid`
FROM `user_source_accounts`
WHERE `profileid` = '100'))
AND `id` NOT IN (SELECT `postid`
FROM `user_posts_removed`
WHERE `profileid` = '100')
AND `live` = '1'
AND `added` >= Date_sub(Now(), INTERVAL 1 month)
AND `popularity` > 1
ORDER BY `popularity` DESC
LIMIT 50
Thank you.
Edit:
I am using MySQL version 5.7.24, so unfortunately the row_number() function will not work in this instance.
mysql sql
mysql sql
edited Nov 21 at 10:10
asked Nov 20 at 18:56
John Cliven
83212
83212
1
What is the MySQL server version ? Also, there is just too manyIN(..
based subqueries. This will not scale well when data gets bigger.
– Madhur Bhaiya
Nov 20 at 18:59
add a comment |
1
What is the MySQL server version ? Also, there is just too manyIN(..
based subqueries. This will not scale well when data gets bigger.
– Madhur Bhaiya
Nov 20 at 18:59
1
1
What is the MySQL server version ? Also, there is just too many
IN(..
based subqueries. This will not scale well when data gets bigger.– Madhur Bhaiya
Nov 20 at 18:59
What is the MySQL server version ? Also, there is just too many
IN(..
based subqueries. This will not scale well when data gets bigger.– Madhur Bhaiya
Nov 20 at 18:59
add a comment |
2 Answers
2
active
oldest
votes
In MySQL 8+, you would simply use row_number()
:
select sp.*
from (select sp.*,
row_number() over (partition by posted_by order by popularity desc) as seqnum
from source_posts sp
) sp
where seqnum <= 5
order by popularity desc
limit 50;
I'm not sure what the rest of your query is doing, because it is not described in your question. You can, of course, add additional filtering criteria or join
s.
EDIT:
In earlier versions, you can use variables:
select sp.*
from (select sp.*,
(@rn := if(@p = posted_by, @rn + 1,
if(@p := posted_by, 1, 1)
)
) as rn
from (select sp.*
from source_posts sp
order by posted_by, popularity desc
) sp cross join
(select @p := '', @rn := 0) params
) sp
where rn <= 5
order by popularity desc
limit 50;
Thank you - this does work locally however the legacy server that runs my database is on MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:11
add a comment |
Could try the row number function. Using that, it would assign each employee a distinct "id." So if one employee had 50 records, only those with a row_number (named as "rank") less than or equal to 5 would be returned.
Select *
from(
SELECT `source_posts.*`, row_number() over (partition by `username` order by `popularity` desc) as rank
FROM `source_posts`
WHERE `posted_by` IN (SELECT `username`
FROM `source_accounts`
WHERE `id` IN (SELECT `sourceid`
FROM `user_source_accounts`
WHERE `profileid` = '100'))
AND `id` NOT IN (SELECT `postid`
FROM `user_posts_removed`
WHERE `profileid` = '100')
AND `live` = '1'
AND `added` >= Date_sub(Now(), INTERVAL 1 month)
AND `popularity` > 1
ORDER BY `popularity` DESC
LIMIT 50 `enter code here`)
where rank <= 5
This works great locally, however I am running this on a legacy server that uses MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:10
Start with this link. stackoverflow.com/questions/3333665/rank-function-in-mysql ... I will play around with my personal mysql database to see how you would include the order by popularity descending.
– ayellowbusman
Nov 22 at 3:43
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53399742%2fmysql-limit-field-to-5-maximum-occurrences%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
In MySQL 8+, you would simply use row_number()
:
select sp.*
from (select sp.*,
row_number() over (partition by posted_by order by popularity desc) as seqnum
from source_posts sp
) sp
where seqnum <= 5
order by popularity desc
limit 50;
I'm not sure what the rest of your query is doing, because it is not described in your question. You can, of course, add additional filtering criteria or join
s.
EDIT:
In earlier versions, you can use variables:
select sp.*
from (select sp.*,
(@rn := if(@p = posted_by, @rn + 1,
if(@p := posted_by, 1, 1)
)
) as rn
from (select sp.*
from source_posts sp
order by posted_by, popularity desc
) sp cross join
(select @p := '', @rn := 0) params
) sp
where rn <= 5
order by popularity desc
limit 50;
Thank you - this does work locally however the legacy server that runs my database is on MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:11
add a comment |
In MySQL 8+, you would simply use row_number()
:
select sp.*
from (select sp.*,
row_number() over (partition by posted_by order by popularity desc) as seqnum
from source_posts sp
) sp
where seqnum <= 5
order by popularity desc
limit 50;
I'm not sure what the rest of your query is doing, because it is not described in your question. You can, of course, add additional filtering criteria or join
s.
EDIT:
In earlier versions, you can use variables:
select sp.*
from (select sp.*,
(@rn := if(@p = posted_by, @rn + 1,
if(@p := posted_by, 1, 1)
)
) as rn
from (select sp.*
from source_posts sp
order by posted_by, popularity desc
) sp cross join
(select @p := '', @rn := 0) params
) sp
where rn <= 5
order by popularity desc
limit 50;
Thank you - this does work locally however the legacy server that runs my database is on MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:11
add a comment |
In MySQL 8+, you would simply use row_number()
:
select sp.*
from (select sp.*,
row_number() over (partition by posted_by order by popularity desc) as seqnum
from source_posts sp
) sp
where seqnum <= 5
order by popularity desc
limit 50;
I'm not sure what the rest of your query is doing, because it is not described in your question. You can, of course, add additional filtering criteria or join
s.
EDIT:
In earlier versions, you can use variables:
select sp.*
from (select sp.*,
(@rn := if(@p = posted_by, @rn + 1,
if(@p := posted_by, 1, 1)
)
) as rn
from (select sp.*
from source_posts sp
order by posted_by, popularity desc
) sp cross join
(select @p := '', @rn := 0) params
) sp
where rn <= 5
order by popularity desc
limit 50;
In MySQL 8+, you would simply use row_number()
:
select sp.*
from (select sp.*,
row_number() over (partition by posted_by order by popularity desc) as seqnum
from source_posts sp
) sp
where seqnum <= 5
order by popularity desc
limit 50;
I'm not sure what the rest of your query is doing, because it is not described in your question. You can, of course, add additional filtering criteria or join
s.
EDIT:
In earlier versions, you can use variables:
select sp.*
from (select sp.*,
(@rn := if(@p = posted_by, @rn + 1,
if(@p := posted_by, 1, 1)
)
) as rn
from (select sp.*
from source_posts sp
order by posted_by, popularity desc
) sp cross join
(select @p := '', @rn := 0) params
) sp
where rn <= 5
order by popularity desc
limit 50;
edited Nov 21 at 11:32
answered Nov 20 at 18:59
Gordon Linoff
755k35290398
755k35290398
Thank you - this does work locally however the legacy server that runs my database is on MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:11
add a comment |
Thank you - this does work locally however the legacy server that runs my database is on MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:11
Thank you - this does work locally however the legacy server that runs my database is on MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:11
Thank you - this does work locally however the legacy server that runs my database is on MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:11
add a comment |
Could try the row number function. Using that, it would assign each employee a distinct "id." So if one employee had 50 records, only those with a row_number (named as "rank") less than or equal to 5 would be returned.
Select *
from(
SELECT `source_posts.*`, row_number() over (partition by `username` order by `popularity` desc) as rank
FROM `source_posts`
WHERE `posted_by` IN (SELECT `username`
FROM `source_accounts`
WHERE `id` IN (SELECT `sourceid`
FROM `user_source_accounts`
WHERE `profileid` = '100'))
AND `id` NOT IN (SELECT `postid`
FROM `user_posts_removed`
WHERE `profileid` = '100')
AND `live` = '1'
AND `added` >= Date_sub(Now(), INTERVAL 1 month)
AND `popularity` > 1
ORDER BY `popularity` DESC
LIMIT 50 `enter code here`)
where rank <= 5
This works great locally, however I am running this on a legacy server that uses MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:10
Start with this link. stackoverflow.com/questions/3333665/rank-function-in-mysql ... I will play around with my personal mysql database to see how you would include the order by popularity descending.
– ayellowbusman
Nov 22 at 3:43
add a comment |
Could try the row number function. Using that, it would assign each employee a distinct "id." So if one employee had 50 records, only those with a row_number (named as "rank") less than or equal to 5 would be returned.
Select *
from(
SELECT `source_posts.*`, row_number() over (partition by `username` order by `popularity` desc) as rank
FROM `source_posts`
WHERE `posted_by` IN (SELECT `username`
FROM `source_accounts`
WHERE `id` IN (SELECT `sourceid`
FROM `user_source_accounts`
WHERE `profileid` = '100'))
AND `id` NOT IN (SELECT `postid`
FROM `user_posts_removed`
WHERE `profileid` = '100')
AND `live` = '1'
AND `added` >= Date_sub(Now(), INTERVAL 1 month)
AND `popularity` > 1
ORDER BY `popularity` DESC
LIMIT 50 `enter code here`)
where rank <= 5
This works great locally, however I am running this on a legacy server that uses MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:10
Start with this link. stackoverflow.com/questions/3333665/rank-function-in-mysql ... I will play around with my personal mysql database to see how you would include the order by popularity descending.
– ayellowbusman
Nov 22 at 3:43
add a comment |
Could try the row number function. Using that, it would assign each employee a distinct "id." So if one employee had 50 records, only those with a row_number (named as "rank") less than or equal to 5 would be returned.
Select *
from(
SELECT `source_posts.*`, row_number() over (partition by `username` order by `popularity` desc) as rank
FROM `source_posts`
WHERE `posted_by` IN (SELECT `username`
FROM `source_accounts`
WHERE `id` IN (SELECT `sourceid`
FROM `user_source_accounts`
WHERE `profileid` = '100'))
AND `id` NOT IN (SELECT `postid`
FROM `user_posts_removed`
WHERE `profileid` = '100')
AND `live` = '1'
AND `added` >= Date_sub(Now(), INTERVAL 1 month)
AND `popularity` > 1
ORDER BY `popularity` DESC
LIMIT 50 `enter code here`)
where rank <= 5
Could try the row number function. Using that, it would assign each employee a distinct "id." So if one employee had 50 records, only those with a row_number (named as "rank") less than or equal to 5 would be returned.
Select *
from(
SELECT `source_posts.*`, row_number() over (partition by `username` order by `popularity` desc) as rank
FROM `source_posts`
WHERE `posted_by` IN (SELECT `username`
FROM `source_accounts`
WHERE `id` IN (SELECT `sourceid`
FROM `user_source_accounts`
WHERE `profileid` = '100'))
AND `id` NOT IN (SELECT `postid`
FROM `user_posts_removed`
WHERE `profileid` = '100')
AND `live` = '1'
AND `added` >= Date_sub(Now(), INTERVAL 1 month)
AND `popularity` > 1
ORDER BY `popularity` DESC
LIMIT 50 `enter code here`)
where rank <= 5
answered Nov 20 at 19:04
ayellowbusman
288
288
This works great locally, however I am running this on a legacy server that uses MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:10
Start with this link. stackoverflow.com/questions/3333665/rank-function-in-mysql ... I will play around with my personal mysql database to see how you would include the order by popularity descending.
– ayellowbusman
Nov 22 at 3:43
add a comment |
This works great locally, however I am running this on a legacy server that uses MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:10
Start with this link. stackoverflow.com/questions/3333665/rank-function-in-mysql ... I will play around with my personal mysql database to see how you would include the order by popularity descending.
– ayellowbusman
Nov 22 at 3:43
This works great locally, however I am running this on a legacy server that uses MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:10
This works great locally, however I am running this on a legacy server that uses MySQL version 5.7.24. Is there any alternative?
– John Cliven
Nov 21 at 10:10
Start with this link. stackoverflow.com/questions/3333665/rank-function-in-mysql ... I will play around with my personal mysql database to see how you would include the order by popularity descending.
– ayellowbusman
Nov 22 at 3:43
Start with this link. stackoverflow.com/questions/3333665/rank-function-in-mysql ... I will play around with my personal mysql database to see how you would include the order by popularity descending.
– ayellowbusman
Nov 22 at 3:43
add a comment |
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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53399742%2fmysql-limit-field-to-5-maximum-occurrences%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
1
What is the MySQL server version ? Also, there is just too many
IN(..
based subqueries. This will not scale well when data gets bigger.– Madhur Bhaiya
Nov 20 at 18:59