Здравствуйте. Такая проблема.
Есть таблица со статьями - article
Есть таблица с комментариями - comments
Есть таблица с тегами - tags и промежуточная таблица между article и tags - articles_tags
Задача: запрос на вывод статей с количеством комментариев и тегами.
Проблема:
Следующий запрос ->
$model = Articles::find()
->select(['articles.*', 'categories.name AS category_name', 'COUNT(comments.id) AS comment_count'])
->joinWith(['category', 'tags', 'comment'])
->groupBy('articles.id')
->all();
<- не может правильно сосчитать количество комментариев. Причем косячит с интересной деталью - если тегов 0 или 1 - все правильно считает. Если тегов Х (где Х >1), то количество комментариев будет равно реальное ко-во комментариев * Х. Я так понимаю, что на каждый тег создается свой дубль записи и COUNT проходится по всем ним и суммирует количество комментов у дублей.
Как правильно переписать запрос? Заранее спасибо за помощь.
Неправильный результат при использовании агрегатной функции
Re: Неправильный результат при использовании агрегатной функции
Код: Выделить всё
echo Articles::find()
->select(['articles.*', 'categories.name AS category_name', 'COUNT(comments.id) AS comment_count'])
->joinWith(['category', 'tags', 'comment'])
->groupBy('articles.id')
->createCommand()
->getRawSql();
-
- Сообщения: 179
- Зарегистрирован: 2018.02.05, 13:41
- Контактная информация:
Re: Неправильный результат при использовании агрегатной функции
может количество считать в select
Код: Выделить всё
SELECT (SELECT count(*) FROM comments WHERE articles.id = article_id) as comment_count, ... FROM ...
Re: Неправильный результат при использовании агрегатной функции
Код: Выделить всё
$model = Articles::find()
->select(['articles.*', 'categories.name AS category_name', 'COUNT(comments.id) AS comment_count'])
->joinWith(['comment'])
->with(['category', 'tags'])
->groupBy('articles.id')
->all();
А связанные данные нужно запрашивать через with() а не через joinWith()
Re: Неправильный результат при использовании агрегатной функции
Да, решил проблему при помощи соотнесенного подзапроса. Получилось норм и фильтрация и сортировка работают. Вот, может кому пригодится потом:
$sub_query = (new Query())->select('COUNT(*)')
->from('comments')
//условие без квадратных скобок, иначе QueryBuilder будет экранировать второй аргумент и в запрос пойдет обычная строка, а не имя_таблицы.имя_столбца, даже если имя таблицы записано в фигурных скобках!
->where('comments.article_id = {{articles}}.id');
$model = Articles::find()
->select(['articles.*', 'categories.name AS category_name', 'comment_count' => $sub_query, 'users.username AS author_name'])
->joinWith(['category', 'tags', 'user', 'comment'])
->groupBy('articles.id')
->andWhere(['<=', 'date_public', date('o-m-d H:i:s')])
->orderBy(['date_public' => SORT_DESC])
->all();
$sub_query = (new Query())->select('COUNT(*)')
->from('comments')
//условие без квадратных скобок, иначе QueryBuilder будет экранировать второй аргумент и в запрос пойдет обычная строка, а не имя_таблицы.имя_столбца, даже если имя таблицы записано в фигурных скобках!
->where('comments.article_id = {{articles}}.id');
$model = Articles::find()
->select(['articles.*', 'categories.name AS category_name', 'comment_count' => $sub_query, 'users.username AS author_name'])
->joinWith(['category', 'tags', 'user', 'comment'])
->groupBy('articles.id')
->andWhere(['<=', 'date_public', date('o-m-d H:i:s')])
->orderBy(['date_public' => SORT_DESC])
->all();