Неправильный результат при использовании агрегатной функции

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
ViRuS-X
Сообщения: 31
Зарегистрирован: 2017.04.19, 01:33

Неправильный результат при использовании агрегатной функции

Сообщение ViRuS-X »

Здравствуйте. Такая проблема.
Есть таблица со статьями - 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 проходится по всем ним и суммирует количество комментов у дублей.

Как правильно переписать запрос? Заранее спасибо за помощь.
Аватара пользователя
SiZE
Сообщения: 2817
Зарегистрирован: 2011.09.21, 12:39
Откуда: Perm
Контактная информация:

Re: Неправильный результат при использовании агрегатной функции

Сообщение SiZE »

Код: Выделить всё

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();
Ты в принципе правильно мыслишь. Открой через любой SQL менджер и все увидишь, тут программирование, а не прогноз погоды. :) Сколько строк будет с comments.id NOT NULL столько и выдаст тебе COUNT(comments.id).
BalykhinAS
Сообщения: 179
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Неправильный результат при использовании агрегатной функции

Сообщение BalykhinAS »

может количество считать в select

Код: Выделить всё

SELECT (SELECT count(*) FROM comments WHERE articles.id = article_id) as comment_count, ... FROM ...
andku83
Сообщения: 988
Зарегистрирован: 2016.07.01, 10:24
Откуда: Харьков

Re: Неправильный результат при использовании агрегатной функции

Сообщение andku83 »

Код: Выделить всё

$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();
Но по идее join с подзапросом каунта комментариев должен быть эффективнее.
А связанные данные нужно запрашивать через with() а не через joinWith()
ViRuS-X
Сообщения: 31
Зарегистрирован: 2017.04.19, 01:33

Re: Неправильный результат при использовании агрегатной функции

Сообщение ViRuS-X »

Да, решил проблему при помощи соотнесенного подзапроса. Получилось норм и фильтрация и сортировка работают. Вот, может кому пригодится потом:
$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();
Ответить