I have a gallery of "Leaders" on my site, where the top users in 5 different categories are selected by a DESC LIMIT 1; the gallery is generated with 5 separate INNER JOIN between the stats and login tables, but all the SELECT clauses are identical:
$cat1wins="SELECT stats.login_id, stats.cat1wins, login.user, login.picture,
login.statement FROM stats INNER JOIN login ON stats.login_id=login.login_id ORDER by
stats.cat1wins DESC LIMIT 1";
$cat2wins="SELECT stats.login_id, stats.cat2wins, login.user, login.picture,
login.statement FROM stats INNER JOIN login ON stats.login_id=login.login_id ORDER by
stats.cat2wins DESC LIMIT 1";
$cat3wins="SELECT stats.login_id, stats.cat3wins, login.user, login.picture,
login.statement FROM stats INNER JOIN login ON stats.login_id=login.login_id ORDER by
stats.cat3wins DESC LIMIT 1";
$cat4wins="SELECT stats.login_id, stats.cat4wins, login.user, login.picture,
login.statement FROM stats INNER JOIN login ON stats.login_id=login.login_id ORDER by
stats.cat4wins DESC LIMIT 1";
$cat5wins="SELECT stats.login_id, stats.cat5wins, login.user, login.picture,
login.statement FROM stats INNER JOIN login ON stats.login_id=login.login_id ORDER by
stats.cat5wins DESC LIMIT 1";
For each category, a WHILE loop extracts the proper table cell (shown here with cat1)
$result1 = mysqli_query($con,$cat1wins);
WHILE ($Category1Wins = mysqli_fetch_assoc($result1)) {
$Cat1User = $Category1Wins['user'];
$Cat1Statement = $Category1Wins['statement'];
echo "code"; //etc
}
I imagine there must be a better way to do this; I imagine I could start like this:
$catAllwins="SELECT stats.cat1wins, stats.login_id, login.user, login.picture,
login.statement, SELECT stats.cat2wins, stats.login_id, login.user, login.picture,
login.statement,.....SELECT stats.cat5wins, stats.login_id, login.user, login.picture,
login.statement FROM stats INNER JOIN login ON stats.login_id=login.login_id";
and then use a WHILE loop on the results of each SELECT statement within $catAllwins to generate 5 separate arrays that can then be sorted with a natsort . However, I am not sure how to extract the proper SELECT statements. I was thinking I could say something like:
$catAllwins="SELECT stats.cat1wins, stats.login_id, login.user, login.picture,
login.statement AS 'array1', SELECT stats.cat2wins, stats.login_id, login.user,
login.picture, login.statement AS 'array2',.....SELECT stats.cat5wins, stats.login_id,
login.user, login.picture, login.statement AS 'array5' FROM stats INNER JOIN login ON
stats.login_id=login.login_id";
$resultAll = mysqli_query($con, $catAllwins)
$Cat1WinsArray = $resultAll['array1'];
$Cat2WinsArray = $resultAll['array2'];
$Cat3WinsArray = $resultAll['array3'];
$Cat4WinsArray = $resultAll['array4'];
$Cat5WinsArray = $resultAll['array5'];
then sort the arrays with natsort (one example shown)
$SortedCat1WinsArray = natsort($Cat1WinsArray);
then add array_reverse for descending order:
$DescSortedCat1WinsArray = array_reverse($SortedCat1WinsArray);
then WHILE this array to extract each component I need (eg, $row['picture'], $row['login_id'], etc.). Does this sound remotely plausible? I would appreciate any feedback! Is there an easier way?
You can just UNION the individual select statements together and apply a sort to the resulting union. Here is an example:
(SELECT stats.login_id, stats.cat1wins, login.user, login.picture, login.statement
FROM stats INNER JOIN login ON stats.login_id=login.login_id
ORDER by stats.cat1wins DESC LIMIT 1)
UNION
(SELECT stats.login_id, stats.cat2wins, login.user, login.picture, login.statement
FROM stats INNER JOIN login ON stats.login_id=login.login_id
ORDER by stats.cat2wins DESC LIMIT 1)
UNION
(SELECT stats.login_id, stats.cat3wins, login.user, login.picture, login.statement
FROM stats INNER JOIN login ON stats.login_id=login.login_id
ORDER by stats.cat3wins DESC LIMIT 1)
UNION
(SELECT stats.login_id, stats.cat4wins, login.user, login.picture, login.statement
FROM stats INNER JOIN login ON stats.login_id=login.login_id
ORDER by stats.cat4wins DESC LIMIT 1)
UNION
(SELECT stats.login_id, stats.cat5wins, login.user, login.picture, login.statement
FROM stats INNER JOIN login ON stats.login_id=login.login_id
ORDER by stats.cat5wins DESC LIMIT 1)
ORDER BY /* Whatever you want to sort by. Wasn't clear in the questoin */
Sorting by five different variables is expensive. You might find the following approach to be more efficient:
select l.login_id,
(case when s.cat1wins = smax.max_cat1wins then 'cat1'
when s.cat2wins = smax.max_cat2wins then 'cat2'
when s.cat3wins = smax.max_cat3wins then 'cat3'
when s.cat4wins = smax.max_cat4wins then 'cat4'
when s.cat5wins = smax.max_cat5wins then 'cat5'
end) as which,
(case when s.cat1wins = smax.max_cat1wins then s.cat1wins
when s.cat2wins = smax.max_cat2wins then s.cat2wins
when s.cat3wins = smax.max_cat3wins then s.cat3wins
when s.cat4wins = smax.max_cat4wins then s.cat4wins
when s.cat5wins = smax.max_cat5wins then s.cat5wins
end) as numwins,
l.user, l.picture, l.statement,
from stats s inner join
(select max(stats.cat1wins) as max_cat1wins,
max(stats.cat2wins) as max_cat2wins,
max(stats.cat3wins) as max_cat3wins,
max(stats.cat4wins) as max_cat4wins,
max(stats.cat5wins) as max_cat5wins
from stats
) smax
on s.cat1wins = smax.max_cat1wins or
s.cat2wins = smax.max_cat2wins or
s.cat3wins = smax.max_cat3wins or
s.cat4wins = smax.max_cat4wins or
s.cat5wins = smax.max_cat5wins join
login l
on s.login_id = l.login_id;
There are two important differences in doing it this way, compared to your original five queries. First, if someone is tops in two or more categories, they only appear once here. Second, if mutliple people are tied for the best in one category, all are included.
getting userid for each max categories
What about this? this has no GROUP BY
and needs just 1 full scan.
SELECT
IF(cat1wins >= @mxc1, @mxu1 := login_id, @mxu1) AS userid1,
IF(cat1wins >= @mxc1, @mxc1 := cat1wins, @mxc1) AS max_cat1wins,
IF(cat2wins >= @mxc2, @mxu2 := login_id, @mxu2) AS userid2,
IF(cat2wins >= @mxc2, @mxc2 := cat2wins, @mxc2) AS max_cat2wins,
IF(cat3wins >= @mxc3, @mxu3 := login_id, @mxu3) AS userid3,
IF(cat3wins >= @mxc3, @mxc3 := cat3wins, @mxc3) AS max_cat3wins,
IF(cat4wins >= @mxc4, @mxu4 := login_id, @mxu4) AS userid4,
IF(cat4wins >= @mxc4, @mxc4 := cat4wins, @mxc4) AS max_cat4wins,
IF(cat5wins >= @mxc5, @mxu5 := login_id, @mxu5) AS userid5,
IF(cat5wins >= @mxc5, @mxc5 := cat5wins, @mxc5) AS max_cat5wins
FROM stats, (
SELECT
@mxc1 := 0, @mxc2 := 0, @mxc3 := 0, @mxc4 := 0, @mxc5 := 0,
@mxu1 := 0, @mxu2 := 0, @mxu3 := 0, @mxu4 := 0, @mxu5 := 0
) x;
finally we get login information using join with login table
Please note that following query returns 1~5 records. (1 for all max user are same. 5 for each max user are diffrent)
SELECT
y.*, login.login_id, login.user, login.picture, login.statement,
IF(y.userid1 = login.login_id, max_cat1wins, NULL) AS max1,
IF(y.userid2 = login.login_id, max_cat2wins, NULL) AS max2,
IF(y.userid3 = login.login_id, max_cat3wins, NULL) AS max3,
IF(y.userid4 = login.login_id, max_cat4wins, NULL) AS max4,
IF(y.userid5 = login.login_id, max_cat5wins, NULL) AS max5
FROM
(
SELECT
IF(cat1wins >= @mxc1, @mxu1 := login_id, @mxu1) AS userid1,
IF(cat1wins >= @mxc1, @mxc1 := cat1wins, @mxc1) AS max_cat1wins,
IF(cat2wins >= @mxc2, @mxu2 := login_id, @mxu2) AS userid2,
IF(cat2wins >= @mxc2, @mxc2 := cat2wins, @mxc2) AS max_cat2wins,
IF(cat3wins >= @mxc3, @mxu3 := login_id, @mxu3) AS userid3,
IF(cat3wins >= @mxc3, @mxc3 := cat3wins, @mxc3) AS max_cat3wins,
IF(cat4wins >= @mxc4, @mxu4 := login_id, @mxu4) AS userid4,
IF(cat4wins >= @mxc4, @mxc4 := cat4wins, @mxc4) AS max_cat4wins,
IF(cat5wins >= @mxc5, @mxu5 := login_id, @mxu5) AS userid5,
IF(cat5wins >= @mxc5, @mxc5 := cat5wins, @mxc5) AS max_cat5wins
FROM stats, (
SELECT
@mxc1 := 0, @mxc2 := 0, @mxc3 := 0, @mxc4 := 0, @mxc5 := 0,
@mxu1 := 0, @mxu2 := 0, @mxu3 := 0, @mxu4 := 0, @mxu5 := 0
) x
) y INNER JOIN login
WHERE login.login_id IN (userid1, userid2, userid3, userid4, userid5);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.