SQL 记录检索

Posted

技术标签:

【中文标题】SQL 记录检索【英文标题】:SQL record retrieval 【发布时间】:2018-12-10 20:25:56 【问题描述】:

晚安社区,

我需要帮助才能从 mysql 表中检索记录,如下所示。请注意我的目标结果:

以下是我目前的方法,它在少量行上效果很好,但在数千甚至数百行上运行速度非常慢。

public function usersTopRecruits()
    $tempUID = array();
    $mainAssocArr = array();
    for ($i=0; $i < User::count(); $i++)  
        if($i == 0)
            $offset = 0;
        
        else           
            $offset = $this->take * $i;
        

        $users = User::take($this->take)->offset($offset)->get();

        foreach ($users as $value) 
            $refCnts = User::where('referral', $value->aff_id)->count();

            if($refCnts > 0)
                $tempUID['userAffID'] = $value->aff_id;
                $tempUID['userrecruits'] = $refCnts;
                $mainAssocArr[] = $tempUID;
            
        
    //End of For loop

    //Here, i tried to sort by highest recruits

    foreach ($mainAssocArr as $key => $row) 
        $desc[$key]  = $row['userrecruits'];
        $asc[$key] = $row['userAffID'];
    

    array_multisort($desc, SORT_DESC, $asc, SORT_ASC, $mainAssocArr);

    return $mainAssocArr;

当月:

public function userTopRecruitsCurrMonth()
    $tempUID = array();
    $mainAssocArr = array();
    for ($i=0; $i < User::count(); $i++)  
        if($i == 0)
            $offset = 0;
        
        else           
            $offset = $this->take * $i;
        

        $users = User::take($this->take)->offset($offset)->get();

        foreach ($users as $value) 
            $refCnts = User::where('referral', $value->aff_id)->where('signup_date', '>=', 'startDateOfCurrentMonth')->count();

            if($refCnts > 0)
                $tempUID['userAffID'] = $value->aff_id;
                $tempUID['userRecruits'] = $refCnts;
                $mainAssocArr[] = $tempUID;
            
        
    //End of For loop


    foreach ($mainAssocArr as $key => $row) 
        $volume[$key]  = $row['userRecruits'];
        $edition[$key] = $row['userAffID'];
    

    array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $mainAssocArr);

    return $mainAssocArr;

任何帮助或建议将不胜感激。

注意:我使用的是 Eloquent 模型,但没有使用“laravel”

【问题讨论】:

为什么是 标签?你想要一个 SQL 查询吗? 是的,查询构建器。对不起,我不是他们的粉丝。就个人而言,我可能会做一个(相关的)子查询来计算总数,然后加入它来进行排序。这是一个必须计算整个数据库的聚合查询,如果您可以将数字烘焙并维护它,它会快得多。 @ArtisticPhoenix 感谢您的评论。您认为可以解决或有助于解决问题的任何示例查询或子查询? 是的,DbFiddle 如果您想要没有推荐的用户,您可能需要进行左连接而不是内连接 (Join) 如果您想要名字等内容,则存在子查询。因为referral 上的分组会改为为您提供其中一个推荐用户数据,而不是实际用户数据。最好将其作为子查询来执行,因为它构建了一个较小的临时表,然后在同一级别进行所有操作,它还在较小的临时表上进行排序。你甚至可以将 ORDER BY 移动到子查询中,它不会改变任何东西。 For Example 至少据我了解它是如何优化事物的。 【参考方案1】:

根据您的评论,我了解到为您提供 SQL 查询可能会有所帮助。

这个简单的聚合查询将返回出现次数最多(所有时间)的REFERRALs,最高。

SELECT referral, COUNT(*) 
FROM table
GROUP BY referral
ORDER BY COUNT(*) DESC

如果您正在寻找当月的相同结果,那么只需添加一个WHERE 子句:

SELECT referral, COUNT(*) 
FROM table
WHERE YEAR(sigmup_date) = YEAR(NOW()) AND MONTH(sigmup_date) = MONTH(NOW()) 
GROUP BY referral
ORDER BY COUNT(*) DESC

【讨论】:

您的答案看起来不错,但当前月份的部分似乎在 条件下不起作用 @HarrisonOziegbe :正确,我将WHEREGROUP BY 子句排序错误。编辑了我的答案,现在应该可以正常工作了。 欢迎@HarrisonOziegbe,很高兴能帮上忙!【参考方案2】:

我会使用这样的查询:

SELECT
    *
FROM
    users AS u0 
JOIN
(
    SELECT
        u1.REFERRAL AS agg,
        COUNT(u1.REFERRAL) AS total
    FROM 
        users AS u1
    GROUP BY
        u1.REFERRAL
    ORDER BY total DESC
) AS u2
ON
    u2.agg = u0.AFF_ID

子查询允许您通过再次加入表来提取 AFF_ID 正在分组的实际用户的数据。这将为您提供他们的 FIRST_NAME 等信息。如果您不再次加入,您将无法获得这些信息。

它还会构建一个较小的临时表(在内存中),然后如果您在同一级别上执行它(可能,我将不得不深入研究它并解释更多)。

Try it yourself

如果您只想做一个月,我们可以修改子查询以仅计算当月添加的用户:

SELECT
    *
FROM
    users AS u0 
JOIN
(
    SELECT
        u1.REFERRAL AS agg,
        COUNT(u1.REFERRAL) AS total
    FROM 
        users AS u1
    WHERE 
        YEAR(u1.sigmup_date) = YEAR(NOW())
      AND
        MONTH(u1.sigmup_date) = MONTH(NOW())
    GROUP BY
        u1.REFERRAL
    ORDER BY total DESC
) AS u2
ON
    u2.agg = u0.AFF_ID

最后,如果您想要没有推荐任何人的用户,您可能/将不得不使用 LEFT JOIN。

For Example

如果您添加类似

的内容
WHERE
  u2.agg IS NULL

在外部查询的末尾,您可以找到所有没有推荐的用户。

For Example

除了任何优化之外,(对我来说)将它作为子查询来做会更好。

最后一个,如果你不喜欢 NULL 作为总数,你可以使用COALESCE() 来解决这个问题:

SELECT
  u0.*, COALESCE(u2.total,0) AS total
FROM
  users AS u0 
LEFT JOIN
(
  SELECT
      u1.REFERRAL AS agg,
      COUNT(u1.REFERRAL) AS total
  FROM 
      users AS u1
  GROUP BY
      u1.REFERRAL
  ORDER BY total DESC
) AS u2
ON
  u2.agg = u0.AFF_ID

DBFiddle

现在这些都是 0

我发现COALESCE 非常有用,您在代码中要做的工作越少,事情就越容易。如果您可以按照您想要的方式从数据库中格式化数据,那么通常比后者处理数据要好。这可能是使用 fetchAll 之类的东西与必须循环通过它并在 php 中修改它才能使用它之前的区别。

干杯!

【讨论】:

以上是关于SQL 记录检索的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL 中检索记录后立即更新表

如何在 SQL 中检索 PL/SQL 记录类型? [复制]

SQL 检索最新记录,按唯一外键分组

SQL Server:不确定如何检索选定的记录

SQL 和 C# 从数据库中检索单个记录

如何检索 MS SQL 中的最新记录? [复制]