Сложный (ish) присоединяется Вопрос: - PullRequest
0 голосов
/ 12 апреля 2011

У меня есть следующая таблица в базе данных mySQL (примечание: они суммированы, поэтому они относятся к этому вопросу, некоторые столбцы опущены).

author (id, username, password etc.)
thread (id, title, content)
tag (id, name)
reply (id, content)
thread_replies (thread_id, reply_id)
author_replies (author_id, reply_id)
thread_tags (thread_id, tag_id)
author_threads (author_id, thread_id)

Теперь, чтобы получить темы от определенного автора, я обычно делаю это:

SELECT thread.title, thread.id AS thread_id, thread.content, author.username, author.id AS author_id
FROM thread
JOIN author_threads ON thread.id = author_threads.thread_id
JOIN author ON author_threads.author_id = author.id
WHERE author.id = '12'

Это работает нормально, однако, когда я пытаюсь получить теги, связанные с этими потоками:

SELECT thread.title, thread.id AS thread_id, thread.content, author.username, author.id AS author_id, GROUP_CONCAT( DISTINCT tag.name
ORDER BY tag.name DESC
SEPARATOR ',' ) AS tags
FROM thread
JOIN thread_tags ON thread.id = thread_tags.thread_id
JOIN tag ON thread_tags.tag_id = tag.id
JOIN author_threads ON thread.id = author_threads.thread_id
JOIN author ON author_threads.author_id = author.id
WHERE author.id = '12'
LIMIT 0 , 30

Показывает только первый поток и все теги, связанные с этим автором, в одном столбце.

Что я здесь не так делаю?

Кроме того, если бы я хотел посчитать количество ответов, полученных автором для каждой темы, как бы это было сделано?

Ответы [ 2 ]

2 голосов
/ 12 апреля 2011

Поскольку вы используете агрегат в своем запросе (GROUP_CONCAT), ваш запрос группируется.Поскольку у вас нет предложения group by, ваша группа - это полный набор результатов (следовательно, видны все теги, использованные автором).Поскольку MySQL позволяет использовать несгруппированные столбцы в сгруппированных выражениях, вы не получаете сообщение об ошибке, но не получаете запрос, который вам нужен.

Чтобы получить правильные результаты, вам необходимосгруппируйте ваш запрос по thread.id.

select
    thread.title, 
    thread.id as thread_id, 
    thread.content, 
    author.username, 
    author.id as author_id, 
    group_concat(distinct tag.name order by tag.name desc separator ',') as tags

from thread

join thread_tags ON thread.id = thread_tags.thread_id
join tag ON thread_tags.tag_id = tag.id
join author_threads ON thread.id = author_threads.thread_id
join author ON author_threads.author_id = author.id

where author.id = '12'

group by thread.id

limit 0 , 30

. Это должно работать в MySQL, хотя это не ANSI-совместимый SQL, поскольку вы используете несгруппированные столбцы в предложении select без агрегирования.Вы можете оставить все как есть или написать более совместимый SQL и использовать что-то вроде max вокруг всех столбцов, кроме thread.id.Это не будет выглядеть красиво, но будет соответствовать.

SELECT 
    max(thread.title) as title, 
    thread.id as thread_id, 
    max(thread.content) as content, 
    max(author.username) as username, 
    max(author.id) as author_id, 
    group_concat(distinct tag.name order by tag.name desc separator ',') as tags

from thread

join thread_tags ON thread.id = thread_tags.thread_id
join tag ON thread_tags.tag_id = tag.id
join author_threads ON thread.id = author_threads.thread_id
join author ON author_threads.author_id = author.id

where author.id = '12'

group by thread.id

LIMIT 0 , 30

Количество ответов

Вышеуказанный запрос (вместе с вашими исходными запросами) подходит только для получения списка тегов.Вы можете написать эквивалентный запрос для получения количества ответов (при условии, что ответы не являются вложенными, и в этом случае вам придется использовать любые возможности рекурсивного запроса, которые предоставляет MySQL, с которыми я не знаком), но для извлечения обоихв одном запросе требуются подзапросы:

select
    thread.title, 
    thread.id as thread_id, 
    thread.content, 
    author.username, 
    author.id, 
    (select group_concat(distinct tag.name order by tag.name separator ',')

    from thread_tags

    join tag on tag.id = thread_tags.tag_id 

    where thread_tags.thread_id = thread.id) as tags,
    (select count(1) from thread_replies where thread_id = thread.id) as reply_count

from thread

join author_threads ON thread.id = author_threads.thread_id
join author ON author_threads.author_id = author.id

where author.id = '12'

LIMIT 0 , 30

Я удалил group by из этого запроса, потому что наш агрегат был перемещен в подвыбор, то есть внешний запрос больше не группируется.

0 голосов
/ 12 апреля 2011

Я бы сначала запросил потоки и информацию тегов ТОЛЬКО внутри ... Затем, у этого уже будут автор и действительные потоки для присоединения ко всему, что вам нужно ...

Если вы действительно хотите применитьограничение, поместите это на ВНУТРЕННЮЮ «ЗАПРОС», так как это станет основой для объединения таблиц внешнего уровня ... В противном случае вы получите внутренний запрос с сотнями или тысячами записей плюс просто для соединения с другими таблицами и выбора в30 записей ... остановите IT на 30, и все готово.

Вы также можете сделать заказ по большинству текущих потоков при ограничении количества возвращаемых записей.

select STRAIGHT_JOIN
      PreQuery.*,
      Author.username,
      Thread.title,
      Thread.Content

   from 
      ( select STRAIGHT_JOIN
              author_threads.author_id,
              author_threads.thread_id,
              group_concat(distinct tag.name order by tag.name desc separator ',') as tags
           from 
              author_threads
                 join thread_tags
                    on author_threads.thread_id = thread_tags.thread_id
                    join tag
                       on thread_tags.tag_id = tag.id
           where
              author_threads.author_id = '12'
           group by
              author_threads.author_id,
              author_threads.thread_id
           limit 0, 30 ) PreQuery

      join author
         on PreQuery.Author_ID = author.id

      join thread
         on PreQuery.Thread_id = thread.id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...