@LemanRass21

Как правильно использовать JOIN для выборки из нескольких таблиц данные + COUNT(*)?

Здравствуйте!
Есть таблица с записями -`boycotts` с полями (id, title, description, public)
Есть таблица - `likes` с полями (boycottid, userid) - 2 записи о бойкоте с id = 1
Есть таблица - `dislikes` с полями (boycottid, userid) - 3 записи о бойкоте с id = 1
Есть таблица - `subscribtions` с полями (boycottid, userid) - 6 записей о бойкоте с id=1

1. Нужно сделать выборку из таблицы boycotts по `id` при этом включить данные о количестве лайков, дизлайков и подписчиков.
2. Я уже пробовал сконструировать запрос и заметил что колонка с лайками например будет называться COUNT(`likes`.`boycottid`). А обычно я именно по имени столбца и доставал данные из MYSQL результата. Разумеется я смогу в коде написать и такое название столбца но просто это выглядит необычно и наталкивает на мысль "может я что то делаю на верно?".

Вот такой запрос у меня получился:
SELECT 
`boycotts`.`id`, 
`boycotts`.`title`,
 `boycotts`.`description`,
 `boycotts`.`public`, 
 COUNT(`likes`.`boycottid`),
 COUNT(`dislikes`.`boycottid`),
 COUNT(`subscriptions`.`boycottid`)
 FROM
 `boycotts`
 JOIN `likes` ON `likes`.`boycottid`=`boycotts`.`id`
 JOIN `dislikes` ON `dislikes`.`boycottid`=`boycotts`.`id`
 JOIN `subscriptions` ON `subscriptions`.`boycottid`=`boycotts`.`id`
 WHERE `boycotts`.`id`=1


Но он почему то выдает что для первого бойкота и лайков и дизлайков и подписчиков по 36 штук хотя такого количества записей даже нет ни в одной из таблиц.
Хотя если убрать все JOIN кроме одного:
SELECT 
 `boycotts`.`id`,
 `boycotts`.`title`,
 `boycotts`.`description`,
 `boycotts`.`public`,
  COUNT(`likes`.`boycottid`)
FROM 
 `boycotts` 
JOIN
 `likes` 
ON
 `likes`.`boycottid`=`boycotts`.`id` 
WHERE
 `boycotts`.`id`=1

то работает нормально.
  • Вопрос задан
  • 205 просмотров
Решения вопроса 2
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
SELECT `b`.`id`, `b`.`title`, `b`.`description`, `b`.`public`, 
  (SELECT COUNT(*) FROM `likes` WHERE `boycottid` = :boycot_id) AS `likes`,
  (SELECT COUNT(*) FROM `dislikes` WHERE `boycottid` = :boycot_id) AS `dislikes`,
  (SELECT COUNT(*) FROM `subscriptions` WHERE `boycottid` = :boycot_id) AS `subscriptions`
  FROM (
    SELECT `id`, `title`, `description`, `public` FROM `boycotts` WHERE `id` = :boycot_id
  ) AS `b`

Но это только если нужно для конкретного id.
Ответ написан
xpert13
@xpert13
Full Stack Developer
Правильно делать так:
В таблице boycotts добавить поля likes_count, dislikes_count, subscribtions_count и пересчитывать их значения каждый раз, когда будет добавляться или удалятся запись из соответствующей полю таблице.

Плюсы:
1. Нормальная выборка нужных вам данных
2. Меньшая нагрузка при выборке данных (этот километровый джоин мало того, что не может решить вашу задачу вообще никак и вам нужно делать несколько отдельных селектов, так он еще будет прилично тормозить при большом количестве данных и/или больших нагрузках)
3. В перспективе больше возможностей (вы сможете находить boycotts по количеству лайков, дизлайков, подписок)

Минусы:
1. Чуть больше телодвижений при создании/удалении лайков, дизлайков, подписке (на практике неощутимо)

---

P.S. Чтобы колонка с результатами не называлась "COUNT(`likes`.`boycottid`)" используйте ключевое слово as и задавайте нужное вам название.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы