1

我有一个查询,我用它来构建一组数据,这些数据应该包含按每个管理员 ID 评分的前 3 名用户。现在因为我不知道如何使用 SQL 来实现这一点,所以我分别为每个管理员获取顶级用户,然后将它们推送到一个数组中。此外,由于调用 sth->fetchAll(),然后调用 array_merge(),会导致在第二次迭代和以后的迭代中有重复的数组键,因此会导致致命错误,我还有一个内部迭代(循环)第一个,它从结果集中获取每一行并将其推送到我保存格式化结果的数组中。在我看来,这会导致 n * 3 次迭代,其中 n * 3 -1 太多了。

另外,一个困扰我很久的顺便问一下:在禁用 PDO 模拟准备好的语句的情况下,是否没有办法将参数或值绑定到 SQL 语言组件(例如 LIMIT 等)?代码:

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() - 间隔 10 天, 1),(1, NOW() - 间隔 1 天, 0), (1, NOW() - 间隔 100 天, 1) , (1, NOW() - 间隔 8 天, 0),

(2, NOW() - 间隔 1 天, 1), (2, NOW() - 间隔 100 天, 1), (2, NOW() - 间隔 5 天, 1), (2, NOW(), 0 ),

(3, NOW(), 0), (3, NOW() - 间隔 1 天, 0), (3, NOW() - 100 天, 1), (3, NOW() - 间隔 4 天, 0) , (3, NOW() - 间隔 5 天, 0)

根据@VolkerK 的要求编辑,粗体是查询应该选择的行,前 3 个热门用户,在他们的 last_updated 列中也有最新的值,或者如果有较少的热门用户,则只有最新的用户此特定管理员的 tan 3

4

2 回答 2

0

没有。看来您已经在使用正确的方法了。
虽然你也可以绑定 $count 。此外,虽然调用 $sth->fetchAll(),然后调用 array_merge(),不会导致重复键(这是不可能的,请注意),我不会将所有用户合并到单个数组中,而是将所有用户合并到一个数组中他们由他们的管理员

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 名。因此,可以循环调整查询
  • 不要相信你的感觉,但要衡量某些数字。如果此功能运行速度太慢而妨碍整个应用程序 - 继续优化。如果没有 - 我相信还有其他一些你可以花时间做的事情
于 2013-04-30T12:36:45.657 回答
-2

我不会在循环中执行这样的查询。第一个解决方案是用于… 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

于 2013-04-30T12:37:21.297 回答