1

私は一連のデータを作成するために使用しているクエリを持っています。これには、各管理者 ID ごとの評価で上位 3 人のユーザーが正確に含まれているはずです。SQL を使用してこれを実現する方法がわからないため、各管理者の上位ユーザーを個別に取得してから、それらを配列にプッシュしています。さらに、sth->fetchAll() を呼び出してから array_merge() を呼び出すと、2 回目以降の反復で配列キーが重複し、致命的なエラーが発生するため、内部反復 (ループ) もあります。最初のものは、結果セットから各行をフェッチし、フォーマットされた結果を保持する配列にプッシュします。私の謙虚な意見では、これは n * 3 -1 多すぎる n * 3 回の反復を引き起こします。

また、かなり長い間私を悩ませてきた BTW の質問: PDO エミュレートされた準備済みステートメントが無効になっている LIMIT などの SQL 言語コンポーネントにパラメーターまたは値をバインドする方法がないというのは本当ですか?. コード:

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) VALUES (1, NOW() - INTERVAL 10 DAY, 1),(1, NOW() - INTERVAL 1 DAY, 0), (1, NOW() - INTERVAL 100 DAY , 1) , (1, NOW() - INTERVAL 8 DAY, 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() - INTERVAL 5 DAY, 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 )
{
    /* … */
}

3 つのエントリへの制限は、元の入力を配列内の 3 つのエントリに制限することによって達成されます$admins

于 2013-04-30T12:37:21.297 に答える