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”
【问题讨论】:
为什么是referral
上的分组会改为为您提供其中一个推荐用户数据,而不是实际用户数据。最好将其作为子查询来执行,因为它构建了一个较小的临时表,然后在同一级别进行所有操作,它还在较小的临时表上进行排序。你甚至可以将 ORDER BY 移动到子查询中,它不会改变任何东西。 For Example 至少据我了解它是如何优化事物的。
【参考方案1】:
根据您的评论,我了解到为您提供 SQL 查询可能会有所帮助。
这个简单的聚合查询将返回出现次数最多(所有时间)的REFERRAL
s,最高。
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
【讨论】:
您的答案看起来不错,但当前月份的部分似乎在WHERE
和GROUP 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 记录检索的主要内容,如果未能解决你的问题,请参考以下文章