简体   繁体   English

是否可以将查询次数从 5 减少到 1?

[英]Possible to reduce number of queries from 5 to 1?

I have a gallery of "Leaders" on my site, where the top users in 5 different categories are selected by a DESC LIMIT 1;我的网站上有一个“领导者”画廊,其中 5 个不同类别的顶级用户由 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:图库是在 stats 和 login 表之间使用 5 个单独的 INNER JOIN 生成的,但所有 SELECT 子句都是相同的:

$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)对于每个类别,WHILE 循环提取正确的表格单元格(此处显示为 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 .然后对 $catAllwins 中的每个 SELECT 语句的结果使用 WHILE 循环以生成 5 个单独的数组,然后可以使用natsort 对其进行排序。 However, I am not sure how to extract the proper SELECT statements.但是,我不确定如何提取正确的 SELECT 语句。 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)然后使用natsort对数组进行排序(显示了一个示例)

$SortedCat1WinsArray = natsort($Cat1WinsArray);

then add array_reverse for descending order:然后按降序添加array_reverse

$DescSortedCat1WinsArray = array_reverse($SortedCat1WinsArray);

then WHILE this array to extract each component I need (eg, $row['picture'], $row['login_id'], etc.).然后在这个数组中提取我需要的每个组件(例如,$row['picture']、$row['login_id'] 等)。 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.您可以将单独的 select 语句联合在一起,并对结果联合应用排序。 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.其次,如果多个人在一个类别中并列最佳,则所有人都包括在内。

Updated更新

getting userid for each max categories获取每个最大类别的用户 ID

What about this?那这个呢? this has no GROUP BY and needs just 1 full scan.这没有GROUP BY ,只需要 1 次完整扫描。

    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最后我们使用 join with login table 来获取登录信息

Please note that following query returns 1~5 records.请注意,以下查询返回 1~5 条记录。 (1 for all max user are same. 5 for each max user are diffrent) (所有最大用户的 1 个相同。每个最大用户的 5 个不同)

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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM