一尘不染

如何以最少的查询获取帖子列表和相关标签

sql

我的表的结构如下:

TAGS(更多类别): ID,标签名称,描述,子弹

帖子: id,标题,网址…

帖子: id,idPost,idTag

用户: id,用户名,userSlug …

*投票 *: id,idPost,idUser

每个帖子最多可以包含五个标签,每个用户只能投票一次。当前,由于尚未实现标记,因此我使用以下查询检索了分页的结果集:

SELECT p.*, u.username, u.userSlug, u.id as userId, 
exists (select 1 from votes v where v.idUser=$id AND p.userId=v.idUser AND p.url = v.url) as voted 
FROM posts p 
JOIN users u ON u.id=p.userId
ORDER BY p.created DESC
LIMIT 10 OFFSET :offset

该查询通过PDO运行,并以JSON格式返回给angularjs ng- repeat。该$id被登录的用户的ID。我在exists子查询中使用它使我的角度视图中的投票按钮变灰(服务器端也有一个检查)。如果有人单击视图中的用户名,则会将其带到一个详细信息页面,在该页面上将显示所有用户的帖子(userSlug以进行救援)。

下一步是将标签包括在结果列表中,在这里我结结巴巴了。列表中的每个帖子都必须包含所有关联的标签(tagName,description,slug),并且每个标签都必须带您进入详细信息页面,在该页面中将显示该特定标签的所有关联的帖子。

我想到的第一个解决方案是在运行前面提到的查询后通过暴力破解我的方法:

foreach ($postsResult as &$post) {
    $sql ="SELECT t.* FROM tags t JOIN poststags pt ON t.id=pt.idTag WHERE pt.idPost=$post->id";
    $stmt=$db->prepare($sql);
    $stmt->execute();
    $tagsResult=$stmt->fetchAll(PDO::FETCH_OBJ);
    $post->tags = $tagsResult;
}
$response->write(json_encode($postsResult));

完成,轻松自如!很多查询会在服务器上产生巨大的压力。而且我们不想这样做。

第二种解决方案是触发另一个查询,该查询将获取与postsResult(s)相关联的所有标签,然后在每个帖子中插入相应的标签,以使PHP能够完成肮脏的工作。

$sql = "
    SELECT t.*, 
           pt.idPost 
      FROM tags t JOIN poststags pt ON t.id=pt.idTag 
     WHERE pt.idPost IN (array of post ids)
";
$stmt=$db->prepare($sql);
$stmt->execute();
$tagsResult = $stmt->fetchAll(PDO::FETCH_OBJ);

foreach ($postsResult as &$post) {
    $arr = array();

    foreach ($tagsResult as $tag) {
        if ($post->id==$tag->idPost) {
            $arr[]=$tag;
        }
    }

    $post->tags = $arr;
}
$response->write(json_encode($postsResult));

有没有更好或更快速的方法来做到这一点?


阅读 146

收藏
2021-05-30

共1个答案

一尘不染

有没有更好或更快速的方法来做到这一点?

如果指数$tagsResultpostId,您可以通过做FETCH_GROUP,那么你就可以取下内嵌套循环抢在一定时间一定所有帖子ID标签:

$sql = "
    SELECT pt.idPost, 鈥� select idPost first so it鈥檚 grouped by this col
           t.*
      FROM tags t JOIN poststags pt ON t.id=pt.idTag 
     WHERE pt.idPost IN (array of post ids)
";

$stmt=$db->prepare($sql);
$stmt->execute();

$tagsResult = $smt->fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_OBJ);
//$tagsResult is now grouped by postId
//see https://stackoverflow.com/questions/5361716/is-there-a-way-to-fetch-associative-array-grouped-by-the-values-of-a-specified-c

foreach($postsResult as &$post) {

    if(isset($tagsResult[$post->id])) {
        $post->tags = $tagsResult[$post->id];
    }
    else {
        $post->tags = array();
    }   
}
2021-05-30