【问题标题】:Query for post and tags in same query在同一查询中查询帖子和标签
【发布时间】:2015-10-24 08:05:45
【问题描述】:

我有 3 个包含这些相关字段的表

帖子 (id,title)
标签 (id,name)
tags_map (id,id_post,id_tag)

我正在尝试这样:

$this->db->select('posts.*,tags.name');
$this->db->from('posts');
$this->db->join('tags_map', 'tags.id_post = posts.id');
$this->db->join('tags', 'tags.id = tags_map.id_tag');
$this->db->group_by('posts.id'); // I can comment this line and same result

看起来是这样,但是即使是多个tags_map记录,它也只返回一个,

如何在一个查询中全部返回?

-编辑-

我有点解决了,但需要 php 处理

$this->db->select('posts.*,group_concat(tags.name) as thetags');

这将返回一个字段 thethags = 'tag1,tag2,tag3'

但我想在标签表上获取其他文件..

并且,例如:

$this->db->select('posts.*,group_concat(tags.name) as 'thetags',group_concat(tags.relevance) as 'therelevances');

我不确定我是否可以信任订单?

【问题讨论】:

  • 旁注:从映射 tags_map (id,id_post,id_tag) 中抛出 id。取而代之的是PRIMARY KEY(id_post, id_tag), INDEX(id_tag, id_post)
  • 你是在问我还是让我知道这个?
  • 建议对该表进行改进。 (以及一般的映射表。)
  • 对不起,我不太明白你的意思(我更像是一个前端开发人员),你想详细说明一下答案吗? :)
  • INDEXes(包括PRIMARY KEYs)是数据库非常重要的一个方面。这就是让他们快速的原因。我正在提出与您提出的问题无关的建议(因此是“评论”,而不是“答案”)

标签: php mysql codeigniter join activerecord


【解决方案1】:

如果您不使用 group_concat 解决方案会更好,因为它不可靠,因为字符长度它有 1024 个字符的默认连接限制,但可以增加它在 manual 中定义,但您不能完全依赖于定义的限制,而不是您可以在应用程序层 (php) 中处理它,就像您正在获取数据以及您想要显示帖子及其相关标签的地方一样,您仍然可以使用按帖子排序的连接查询现在每个帖子都可以有更多多于一个标签,因此结果集将具有重复的帖子数据,因为每个帖子行将有一个标签,而具有相同帖子的另一行将有第二个标签,依此类推,现在当您遍历结果时,通过添加一些检查仅显示每个帖子一次

$this->db->select('p.*,t.*');
$this->db->from('posts p');
$this->db->join('tags_map tm', 't.id_post = p.id');
$this->db->join('tags t', 't.id = tm.id_tag');
$this->db->order_by('p.id asc,t.id asc');
$results = $this->db->get();

在上面的查询中,我添加了t.* 以选择所有帖子及其相关标签,现在在循环中$currentParent 将在循环中有一个以前的帖子ID 检查它是否是同一个帖子,然后如果条件返回假则显示它的标签然后它的一个使用标记(h1)的新帖子显示帖子标题,我已经从两个表中选择了所有列,但您应该只从标签表中添加需要的列,如果帖子和标签表具有相同名称的列,那么在查询中使用不同的别名定义它们

$currentParent = false;
foreach ($results as $post) {
    if ($currentParent != $post->id) {
        echo '<h1>' . $post->title . '</h1>';
        $currentParent = $post->id;
    }
    echo '<p>' . $post->name . '</p>'; /** here list tags info*/
    echo '<p>' . $post->tag_other_details . '</p>'; 
    ...
}

结果标记会像

<h1>Post title 1</h1>
    <p>tag 1</p>
    <p>tag 2</p>
<h1>Post title 2</h1>
    <p>tag 3</p>...

如果您没有显示数据并且您在其他地方(网络服务)使用它,那么仍然使用一个连接查询并通过创建数组/对象来转换您的数据每个帖子都有一个相关标签数组,如下所示

$posts =array();
foreach ($results as $post) {
 $posts[$post->id]['title'] = $post->title;
 $posts[$post->id]['tags'][] =array('id' => $tag->id ,'name' =>$post->name);
}

还有另一种强烈不推荐获取帖子并在循环中通过运行查询获取标签的方法现在这个解决方案可以工作,但会涉及不需要的查询,因此将执行额外的查询每个帖子。

现在,如果您真的想坚持使用 group_concat 方法来回答您的问题 I'm not sure if I can trust the order?,还有一种方法可以在 group_concat 中添加 order by,以便生成的串联标签将被订购,对于第二列,您可以放置​​相同的订购标准

$this->db->select('p.*,group_concat(t.name order by t.id) as thetags,
                       group_concat(t.relevance order by t.id) as therelevances');
$this->db->from('posts p');
$this->db->join('tags_map tm', 't.id_post = p.id');
$this->db->join('tags t', 't.id = tm.id_tag');
$this->db->group_by('p.id');

【讨论】:

    【解决方案2】:

    我觉得应该这样查询

    $this->db->select('posts.*, tags.name');
    $this->db->from('tags_map');
    &this->db->join('posts', 'tags_map.id_post = posts.id');
    $this->db->join('tags', 'tags_map.id_tag = tags.id');
    

    当使用连接时,你应该使用一对多的关系,在这种情况下,tags_map 表作为连接表,为帖子和标签表提供多对一的关系

    【讨论】:

      【解决方案3】:

      试试下面的代码:

      $this->db->select('pt.*,group_concat(tg.name order by tg.id) as thetags,group_concat(tg.relevance order by tg.id) as therelevances');
      $this->db->from('posts pt');
      $this->db->join('tags_map tm', 'tg.id_post = pt.id');
      $this->db->join('tags tg','tg.id =tm.id_tag');
      $this->db->group_by('pt.id');
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多