2011-02-09 3 views
2

Я хочу выбрать все сообщения, которые содержат определенный тег. Я пытаюсь его с этим запросом:sql join problem

SELECT GROUP_CONCAT(t.tag_name) taglist 
FROM posts p 
JOIN posts_tags pt ON p.post_id = pt.post_id 
JOIN tags t ON t.tag_id = pt.tag_id 
WHERE (p.post_private = 0) AND t.tag_name = 'php' 
GROUP BY p.post_id 

Проблема, приведенный выше запрос, выбирает все сообщения, которые содержат php тега, но не выбираю какие-либо из других тегов пост может содержать. Без части AND t.tag_name = 'php' он выбирает каждый тег, который имеет сообщение, но я хочу, чтобы иметь возможность фильтровать по тегам ...

Любые идеи, как это сделать? Я пробовал много вещей, но не могу понять ...

Примеры данных без AND заявления:

|| *taglist* || 
|| php,echo || 
|| c++, cout || 

выборки данных с AND заявлением:

|| *taglist* || 
|| php  || 

Что Я хочу:

|| *taglist* || 
|| php,echo || 

(сообщения, содержащие тег PHP o nly)

+0

RIGHT JOIN? Вы уверены, что это то, что вы хотите? –

+0

Вы правы, мне здесь не нужен, но все еще не работает, хотя – networkprofile

+0

Можете ли вы предоставить образцы данных и каков ваш ожидаемый результат? –

ответ

3
SELECT p.post_id, GROUP_CONCAT(t.tag_name) taglist 
    FROM posts p 
     /* These 2 joins get the list of all tags */ 
     INNER JOIN posts_tags pt 
      ON p.post_id = pt.post_id 
     INNER JOIN tags t 
      ON pt.tag_id = t.tag_id 
     /* These 2 joins guarantee the 'php' tag is included */ 
     INNER JOIN posts_tags pt2 
      ON p.post_id = pt2.post_id 
     INNER JOIN tags t2 
      ON pt2.tag_id = t2.tag_id 
       AND t2.tag_name = 'php' 
    WHERE p.post_private = 0 
    GROUP BY p.post_id 
+0

Спасибо, я не думаю, что нашел бы это. Все еще не совсем понимаю, как работают два нижних соединения. – networkprofile

+0

+1 для не использования подзапроса, а только INNER JOINs. –

+1

@Sled: нижние два соединения совпадают с первыми двумя, за исключением того, что они также включают критерии 'AND t2.tag_name = 'php''. Поскольку они являются соединениями INNER, они гарантируют, что любая возвращаемая запись должна иметь связанный с ней тег php. –

2

Я попытаюсь объяснить, почему ваша первая попытка не работает.

Что вы на самом деле пытаетесь найти, это найти все сообщения, которые один их тегов - 'php'. Но их теги распространены в много строк, поэтому t.tag_name = 'php' не работает, поскольку он отфильтровывает все строки, которые не имеют тега «php».

Если вы хотите, чтобы проверить состояние, которое зависит от многих строк,

вы либо создать подзапрос (найти все post_ids что делать есть PHP тег)

p.post_id IN 
    (SELECT pt2.post_id 
     FROM post_tags pt2 
     JOIN tags t2 
      ON t2.tag_id = pt2.tag_id 
     WHERE t2.tag_name = 'php' 
) 

, но все-таки присоединиться к этим post_ids с все связанные теги.

SELECT GROUP_CONCAT(t.tag_name) taglist 
    FROM posts p 
    JOIN posts_tags pt 
     ON p.post_id = pt.post_id 
    JOIN tags t 
     ON t.tag_id = pt.tag_id 
    WHERE (p.post_private = 0) 
    AND p.post_id IN 
     (SELECT pt2.post_id 
      FROM post_tags pt2 
      JOIN tags t2 
       ON t2.tag_id = pt2.tag_id 
      WHERE t2.tag_name = 'php' 
    ) 
    GROUP BY p.post_id 

Или вы делаете это немного более умно, как показал Stefanelli с еще 2 соединений (которые действуют аналогично подзапроса)

+0

Понимаю, спасибо, что взял на себя труд объяснить! – networkprofile