【问题标题】:How do I get multiple COUNT with multiple JOINS and multiple conditions?如何获得具有多个 JOINS 和多个条件的多个 COUNT?
【发布时间】:2015-05-30 14:59:23
【问题描述】:

我有我无法弄清楚的 SQL (MySQL)。该应用程序正在使用上传的照片,其中一张照片中有许多被标记的参与者,并且有可能在 1 到 5 之间给照片投票。

原始查询获取一张照片的所有投票,并按投票数量和投票的平均值对它们进行排序。

现在我需要限制超过 1 个参与者返回的照片。因此,不应考虑只有 1 位参与者的照片。

简化的架构如下所示。

PHOTOS
----------------------
| id   | title       |
----------------------
| 1    | Fun stuff   |
| 2    | Crazy girls |
| 3    | Single boy  |


PHOTO_VOTES
-------------------------------------------
| photo_id   | grade    | date  | user_id |
-------------------------------------------
| 1          | 3        | …     | 12      |
| 1          | 3        | …     | 12      |
| 2          | 5        | …     | 14      |
| 2          | 4        | …     | 14      |
| 3          | 4        | …     | 15      |
| 3          | 4        | …     | 18      |


PHOTO_PARTICIPANTS
-------------------------
| photo_id   | user_id  |
-------------------------
| 1          | 12       |
| 1          | 21       |
| 1          | 33       |
| 2          | 14       |
| 2          | 33       |
| 3          | 12       |

这是我走了多远:

SELECT vote.photo_id,
  COUNT(vote.photo_id) AS vote_count,
  AVG(vote.grade) AS vote_average,
  COUNT(pp.photo_id) AS participant_count

 FROM photo_votes vote

  LEFT JOIN photos p ON (vote.photo_id = p.id)
  LEFT JOIN photo_participants pp ON (pp.photo_id = p.id)

  GROUP BY vote.post_id, 
   HAVING vote_count >= 2
   AND vote_average >= 3
   AND participant_count > 1

  ORDER BY count DESC, average DESC;

基本上是我想要的结果,不包括只有一位参与者的照片:

VOTES
-----------------------------------------------------------
| photo_id   | vote_count     | average  | participant_count
-----------------------------------------------------------
| 1          | 2              | 3        | 3
| 2          | 2              | 4.5      | 2

更新

事实证明,这是一种非常低效的尝试做我想做的事情的方式。 Gordons 下面的回答确实解决了这个问题,但是当我也想加入照片表中的字段时,“笛卡尔积”问题就变成了一个真正的问题——它变成了一个非常繁重和缓慢的查询。

我最终得到的解决方案是在照片表中添加一个缓存字段,以跟踪照片中有多少参与者。换句话说,我在“照片”中添加了一个“participant_count”字段,每次对参与者表进行更改时都会更新该字段。我还定期运行 cron-job 以确保所有照片 'participant_count' 都是最新的。

【问题讨论】:

  • 您的查询有什么问题?

标签: mysql


【解决方案1】:

首先,您不需要left joins。但这不应该影响结果。问题是您有一个笛卡尔积,因为您与照片有两个 1-n 关系:投票和参与者。

解决这个问题的正确方法是使用子查询:

SELECT pv.photo_id, pv.vote_count, pv.vote_average, pp.participant_count
FROM (SELECT pv.photo_id, count(*) AS vote_count, avg(grade) AS vote_average
       FROM photo_votes pv
       GROUP BY pv.photo_id
      ) pv 
JOIN
      (SELECT pp.photo_id, count(*) AS participant_count
       FROM photo_participants p;
       GROUP bY pv.photo_id
      ) pp
      ON pv.photo_id = pp.photo_id
WHERE pv.vote_count >= 2 AND
      pv.vote_average >= 3 AND
      pp.participant_count > 1
ORDER BY pv.vote_count DESC, pv.vote_average DESC;

请注意,您甚至不需要 photos 表,因为您没有使用其中的任何字段。

【讨论】:

  • 嗨,戈登,感谢您的帮助。除了一些语法错误之外,这正是我想要的。不幸的是,我似乎需要照片表,因为我还需要了解照片上传时间(过去 30 天)的条件。我在您的解决方案之后添加了一个 JOIN 但查询结果非常慢,而且我有些情况被取消了:(
猜你喜欢
  • 2012-04-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-25
  • 1970-01-01
  • 1970-01-01
  • 2014-03-01
  • 2020-03-05
  • 1970-01-01
相关资源
最近更新 更多