【问题标题】:Using COUNT() to get data from 3 joined tables使用 COUNT() 从 3 个连接表中获取数据
【发布时间】:2021-04-01 14:27:37
【问题描述】:

我在 MySql 中有这 4 个表:

用户

  • 用户ID
  • 用户名
  • 密码
  • 其他一些东西

电影

  • 电影ID
  • 姓名
  • 其他一些东西

集合(用户和电影之间的多对多关系):

  • 用户ID
  • 电影ID

评论

  • 评论ID
  • 用户ID
  • 电影ID
  • 其他一些东西

所以基本上我想要的是从用户、评论和收藏中提取数据并显示某种用户统计信息,例如 每个用户留下的评论数量,以及每个用户保存到他们收藏中的电影数量。我以为这只是 3 个表之间的简单连接,但显然我错了。

我认为使用 COUNT() 聚合函数是最好的主意,因此我开始对用户评论和用户收藏分别进行查询,结果很好,两个查询的结果都是正确的。

 SELECT u.userID, username, COUNT(movieID) AS collection_size 
 FROM collection c INNER JOIN USER u ON u.userID=c.userID 
 GROUP BY c.userID


 userID username    collection_size
 7      user        2
 8      user03      6

SELECT u.userID, username, COUNT(movieID) AS review_count 
FROM review r INNER JOIN USER u ON u.userID=r.userID 
GROUP BY r.userID

userID  username    review_count
7       user        1
8       user03      4
10      user05      1

尝试连接所有三个表时会出现问题。我最接近解决问题的是:

SELECT u.userID, username, COUNT(DISTINCT c.movieID) AS collection_size, COUNT(DISTINCT r.movieID) AS review_count
FROM collection c INNER JOIN USER u ON u.userID=c.userID 
INNER JOIN review r ON r.userID=u.userID
GROUP BY u.userID

userID  username    collection_size review_count
7       user        2               1
8       user03      6               4

结果几乎是正确的,但是您可以看到用户 ID 为 10 的用户丢失了,即使他留下了一条评论。这个查询似乎只选择了至少留下了一条评论并且在他们的收藏中至少有一部电影的用户。我已经通过将电影添加到用户 10 的收藏中来验证这一点。然后他正确地出现在结果中。 如何更改查询以显示已留下至少一条评论在他们的收藏中至少有一部电影的用户?

基本上我希望结果是这样的:

userID  username    collection_size review_count
7       user        2               1
8       user03      6               4
10      user05      0               1

【问题讨论】:

    标签: mysql sql count subquery left-join


    【解决方案1】:

    该用户似乎没有集合(您的第一个查询未返回该集合)。您可以改用LEFT JOINs,从用户表开始:

    SELECT u.userID, u.username, 
        COUNT(DISTINCT c.movieID) AS collection_size, 
        COUNT(DISTINCT r.movieID) AS review_count
    FROM usr u 
    LEFT JOIN collection c ON u.userID=c.userID 
    LEFT JOIN review r ON r.userID=u.userID
    GROUP BY u.userID
    

    虽然这样可行,但效率不高。连接将两边的行相乘,然后才计算不同的主键值。我认为使用计数的两个子查询来表达查询会更有效:

    select u.userid, u.username, 
        (select count(*) from collection c where c.userid = u.userid) as collection_size,
        (select count(*) from review     r where r.userid = u.userid) as review_count
    from usr u
    

    【讨论】:

    • 使用左连接我仍然得到与第一次相同的结果,但重组后的查询成功了。非常感谢!
    【解决方案2】:
    SELECT
        a.userid
        ,b.qty_movies
        ,c.qty_reviews
    FROM
        user a
        LEFT OUTER JOIN (
          SELECT
            userid
            ,COUNT(*) qty_movies
          FROM
            collection
          GROUP BY 1
        ) b ON (a.userid = b.userid)
        LEFT OUTER JOIN (
          SELECT
            userid
            ,COUNT(*) qty_reviews
          FROM
            review
          GROUP BY 1    
        ) c ON (a.userid = c.userid)
    ;
    

    https://www.db-fiddle.com/f/fiiwTyoFEuspGyscAh23bG/1

    【讨论】:

      猜你喜欢
      • 2018-12-09
      • 2016-06-06
      • 2019-04-03
      • 1970-01-01
      • 2019-08-03
      • 1970-01-01
      • 1970-01-01
      • 2014-07-10
      • 1970-01-01
      相关资源
      最近更新 更多