使用SQL获取特定标记的所有帖子

时间:2014-09-08 23:28:03

标签: mysql sql codeigniter

我正在使用的博客有3个不同的表格。

第一张表:blog_posts,它有一个ID,标题,内容,user_id(创建帖子的人),created_date和slug。

第二张表:blog_tags,它有一个ID,post_id和tag_id

第3张表:标签,它有ID和标签

我使用表3保存所有标签一次,因此没有重复。然后我使用表2将标签连接到帖子(表1)。

我遇到的问题是从特定标签获取所有帖子,并返回所有其他标签。

我的代码现在只返回我想要查找帖子的标签,但我仍想写出其余的标签,只显示HAS的帖子包含该特定标签......

我通常对SQL很敏锐,但这次我的脑袋完全静止......请帮帮我:) 如果重要的话,我正在使用PHP和CodeIgniter。

提前致谢。

麦克

修改

我将结果打印为json,这给了我以下内容:

{
    "data": [
        {
            "id": "28",
            "title": "blabla",
            "content": "<p>hello<\/p>",
            "user_id": "1",
            "created_date": "2014-08-18 23:57:22",
            "slug": "blabla-2014-08-18-235722"
        },
        {
            "id": "34",
            "title": "test2",
            "content": "<p>test2<\/p>",
            "user_id": "1",
            "created_date": "2014-08-23 21:41:00",
            "slug": "test2-2014-08-23-214100"
        }
    ],
    "success": true
}

在下面的答案的帮助下。我的SQL和代码现在说:

$sql = "SELECT * FROM blog_posts bp
        WHERE EXISTS(SELECT * FROM blog_tags bt INNER join
                     tags t ON t.id = bt.tag_id
                     WHERE bp.id = bt.post_id
                     AND t.id = ".$this->db->escape($tag_id).")";

$results = $this->db->query($sql)->result();

return $results;

我想得的是以下内容:

{
    "data": [
        {
            "id": "28",
            "title": "blabla",
            "content": "<p>hello<\/p>",
            "user_id": "1",
            "created_date": "2014-08-18 23:57:22",
            "slug": "blabla-2014-08-18-235722",
            "tags": [
                {
                    "id": 1
                    "tag": "test",
                },
                {
                    "id": 2
                    "tag": "test2",
                }
            ]
        },
        {
            "id": "34",
            "title": "test2",
            "content": "<p>test2<\/p>",
            "user_id": "1",
            "created_date": "2014-08-23 21:41:00",
            "slug": "test2-2014-08-23-214100"
            "tags": [
                {
                    "id": 3
                    "tag": "testa",
                },
                {
                    "id": 1
                    "tag": "test",
                }
            ]
        }
    ],
    "success": true
} 

3 个答案:

答案 0 :(得分:1)

我假设您很乐意向数据库发送两个请求。

首先,获取给定标签的所有帖子:

SELECT * FROM blog_posts bp 
WHERE EXISTS (SELECT * FROM blog_tags bt INNER JOIN
               tags t ON t.id = bt.tag_id
              WHERE bp.id = bt.post_id
               AND t.tag = @SearchTag)

其次,我想通过帖子链接到您要查找的标签:

SELECT * FROM tags t
WHERE EXISTS ( -- Here we link two tags via blog_tags
               SELECT * FROM blog_tags bt1 INNER JOIN
               blog_tags bt2 ON bt1.post_id = bt2.post_id
                     AND bt1.tag_id != bt2.tag_id INNER JOIN
               tags t ON t.id = bt1.tag_id
               WHERE t.tag = @SearchTag
                  AND t.id = bt2.tag_id
)

答案 1 :(得分:0)

我一气呵成,继续@ Bulat的代码。

SELECT *, 
GROUP_CONCAT(DISTINCT bt.tag_id) as tags_id, 
GROUP_CONCAT(DISTINCT t.tag) as tags
FROM blog_posts bp
INNER JOIN blog_tags bt
ON bt.post_id = bp.id
ON t.id = bt.tag_id
GROUP BY bt.post_id
ORDER BY bp.created_date DESC

然后我将tags和tags_id作为带有foreach循环的数组返回

$results = $this->db->query($sql)->result();

foreach($results as $result) {
  $result->tags_comma = $result->tags;
  strpos($result->tags, ',') ? $result->tags = explode(',', $result->tags) : $result->tags = array($result->tags);
  $result->tags_comma = str_replace(',', ', ', $result->tags_comma);
}

foreach($results as $result) {
  $result->tags_id_comma = $result->tags_id;
  strpos($result->tags_id, ',') ? $result->tags_id = explode(',', $result->tags_id) : $result->tags_id = array($result->tags_id);
  $result->tags_id_comma = str_replace(',', ', ', $result->tags_id_comma);
}

答案 2 :(得分:0)

根据这篇文章经过几个小时后, How to Write Many-To-Many Search Queries in MySQL and Hibernate 我已经找到了一种方法可以一次性完成。到目前为止,它对我有用。

请注意我正在使用此表名: noticias as blog_posts,tags_noticias as blog_tags,tasg as tag

SELECT a.id, a.titulo, GROUP_CONCAT(tags.descripcion) as tags
FROM   noticias a
   INNER JOIN (SELECT   at.id_noticia
               FROM     tags_noticias at
                        INNER JOIN noticias a
                          ON a.id = at.id_noticia
                        INNER JOIN tags t
                          ON t.id = at.id_tag
               WHERE    t.descripcion IN ("tag1","tag2")
               GROUP BY at.id_noticia
               HAVING   Count(at.id_noticia) = 2) aa
     ON a.id = aa.id_noticia 
JOIN tags_noticias ON tags_noticias.id_noticia = a.id 
JOIN tags ON tags.id = tags_noticias.id_tag
GROUP BY tags_noticias.id_noticia