我有一个查询,我用它来构造一组数据,它应该包含每个管理员ID评级的前3个用户。现在,因为我不知道如何使用SQL实现这一点,所以我分别为每个管理员获取顶级用户,然后将它们推入一个数组。此外,由于调用sth->fetchAll(),然后调用array_merge(),将导致在第二次迭代和以后的迭代中有重复的数组键,因此将导致致命错误,因此我还在第一次迭代中有一个内部迭代(循环),它从结果集中获取每一行,并将其推入我保存格式化结果的数组中。这会导致n *3次迭代,在我看来,这是n *3 -1太多了。
还有,一个问题已经困扰我很长一段时间了:是否没有办法将参数或值绑定到SQL语言组件,如LIMIT等禁用PDO模拟准备语句?代码:private function getHotUsers($admins, $count = 3)
{
try{
$conn = DBLink::getInstance();
$rows = array();
$sql = "SELECT user_name, user_id, user_group_id FROM users
WHERE admin_id= :uid AND status=1 ORDER BY is_hot_user DESC,last_updated DESC LIMIT {$count}";
$sth = $conn->prepare($sql);
foreach ($admins as $admin)
{
$sth->bindParam(':uid', $admin, PDO::PARAM_INT);
$sth->execute();
while($row = $sth->fetch(PDO::FETCH_ASSOC)){
$rows[] = $row;
}
}
return $rows;
}
}
| Field | Type | Null | Key | Default | Extra |
+----------------------+------------------+------+-----+---------+----------------+
| user_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| admin_id | int(20) | NO | | NULL | |
| user_title | varchar(450) | NO | | NULL | |
| user_desc | varchar(5000) | NO | | NULL | |
| user_data | longtext | NO | | NULL | |
| user_requirements | varchar(5000) | YES | | NULL | |
| user_experience | varchar(100) | NO | | NULL | |
| location_id | int(11) unsigned | NO | | NULL | |
| comp_id | int(11) | NO | | NULL | |
| role_id | int(10) unsigned | NO | | NULL | |
| user_pass_time | varchar(100) | YES | | NULL | |
| last_updated | datetime | NO | | NULL | |
| is_hot_user | tinyint(1) | NO | | 0 | |
| user_internal_id | int(10) | YES | | NULL | |
+----------------------+------------------+------+-----+---------+----------------+
INSERT INTO USERS(admin_id, last_updated, is hot_user)值(1, now () - interval 10天,1),(1,now () - interval 1天,0),(1,现在()——间隔100天,1),(1,现在()——间隔8天,0),
(2, NOW() - INTERVAL 100天,1),(2,NOW() - INTERVAL 100天,1),(2,现在()-间隔5天,1),(2,现在(),0),
(3,现在(),0)、(3)、现在()——间隔1天,0)、(3)、现在()- 100天,1),(3, NOW() - INTERVAL 4 DAY, 0), (3, NOW() - INTERVAL 5 DAY, 0)
根据@VolkerK的请求编辑,粗体是查询应该选择的行,前3个热门用户,他们的last_updated列中也有最近的值,或者只是最新的用户,如果这个特定的admin的热门用户少于3个
没有。看来你的方法已经正确了。
不过您也可以绑定$count。此外,虽然调用$sth->fetchAll(),然后调用array_merge(),将不导致有重复的键(这是不可能的,请注意),我不会合并所有的用户到一个数组,无论如何,而是按他们的admin分组他们
private function getHotUsers($admins, $count = 3)
{
$conn = DBLink::getInstance();
$rows = array();
$sql = "SELECT user_name, user_id, user_group_id FROM topUsers
WHERE admin_id= :uid AND status=1
ORDER BY is_hot_user DESC,last_updated DESC
LIMIT :coint";
$sth = $conn->prepare($sql);
foreach ($admins as $admin)
{
$sth->bindParam(':uid', $admin, PDO::PARAM_INT);
$sth->bindParam(':count', $count, PDO::PARAM_INT);
$sth->execute();
$rows[$admin] = $sth->fetchAll();
}
return $rows;
}
让你的一些困惑直接:
- 实际上,fetchAll不会凭空创建一个数组。它在内部做同样的循环。所以,没有开销。
- 获得任何你需要运行单独查询的前3名。因此,可以在循环中打开查询
- 不相信你的感觉但测量某些数字。如果这个函数运行得很慢,妨碍了整个应用程序,那么继续优化吧。如果没有,我相信你可以花时间做一些其他的事情。
我不会在循环中执行这样的查询。第一个解决方案是使用… IN (…)
来搜索ID列表(如Rob建议的)。
或者您只是在循环中设置查询和参数,并在循环后执行语句。
$start = 0;
$limit = 100;
$placeholderArray = $valuesArray = array( );
$i = 0;
foreach( $admins as $adminId )
{
$placeholderArray[] = sprintf( ' `admin_id` = :admin%d ', $i );
$valuesArray[sprintf( ':admin%d', $i )] = (int) $adminId;
$i++;
}
$where = ' (' . implode( ' OR ', $placeholderArray ) . ') ';
$sql = sprintf( 'SELECT user_name, user_id, user_group_id
FROM topUsers
WHERE status=1
%s
ORDER BY is_hot_user DESC,last_updated DESC
LIMIT %d,%d;', $where, $start, $limit );
$stmt = $conn->prepare( $sql );
if( $stmt->execute( $valuesArray ) === true )
{
/* … */
}
三个条目的限制是通过将数组$admins
中的原始输入限制为三个条目来实现的。