【问题标题】:SELECT, 2 counts from 2nd table, RIGHT JOIN on 3rdSELECT,从第 2 个表计算 2 个,第 3 个 RIGHT JOIN
【发布时间】:2018-09-20 14:25:40
【问题描述】:

我正在尝试为特定用户(此代码中的#1)收集“关注者”。

我正在从followers 中进行主要选择,因为following 列将拥有用户#1,followers.userid 将拥有执行以下操作的人的用户ID。

接下来,我尝试从experiences 中获取具有关注者用户 ID 的记录计数(该关注者有多少经验?)

接下来,关注者将对每个体验进行评分(1-5 星),我想将这些评分(experiences.stars)相加,以获得所有体验的平均评分。

最后,我想从 users 表中加入关注者用户记录。

我应该以 userid、jobs、stars、*来自用户

SELECT * FROM followers AS F
RIGHT JOIN 
  (SELECT count(id) FROM experiences AS M WHERE M.userid = F.userid) AS jobs
RIGHT JOIN
  (SELECT sum(stars) FROM experiences AS S WHERE S.userid = F.userid) AS stars
RIGHT JOIN 
  users AS U ON U.userid = F.userid
WHERE F.following = 1 /* #1 = the user # I want the follwers of/for */

我也试过了:

SELECT * FROM followers AS F,
  (SELECT count(id) FROM experiences AS M WHERE M.userid = F.userid) AS jobs,
  (SELECT sum(stars) FROM experiences AS S WHERE S.userid = F.userid) AS stars
RIGHT JOIN 
  users AS U ON U.userid = F.userid
WHERE F.following = 1 /* #1 = the user # I want the follwers of/for */

在 cPanel 中,我收到一条错误消息,提示我在两个语句中的 WHERE F.userid 处都有语法错误。

A) 我错过了什么,B) 有没有更好的方法来做到这一点?

【问题讨论】:

  • 您使用RIGHT JOIN的任何特殊原因?本质上没有错;我只是很少看到它在组合良好的查询中使用。
  • 没有真正的原因。我编辑了我的问题并显示了我尝试过的另一个查询。结果相同。除了 F.userid 在 SELECT 中带有 COUNT()
  • 混合“逗号连接”和显式连接也不是一个好主意;逗号连接通常被认为是过时的(充其量),因为它们已经失宠了几十年。

标签: mysql count right-join


【解决方案1】:

在我看来,这样的查询会更容易理解:

SELECT * 
FROM followers AS F
LEFT JOIN users AS U ON U.userid = F.userid
LEFT JOIN (SELECT count(id) FROM experiences AS M WHERE M.userid = **F.userid)** AS jobs
LEFT JOIN (SELECT sum(stars) FROM experiences AS S WHERE S.userid = F.userid) AS stars
WHERE F.following = 1 /* #1 = the user # I want the follwers of/for */
;

您最初拥有的所有那些 RIGHT JOIN 只会为您提供具有两种“类型”体验的追随者。

另外,相关的子查询可能很昂贵(而且您不需要其中两个...实际上,您甚至不需要子查询),所以我也会像这样重新设计它......

SELECT F.*, U.*, count(x.id), sum(x.stars)
FROM followers AS F
LEFT JOIN users AS U ON U.userid = F.userid
LEFT JOIN experiences AS x ON F.userid = x.user_id
WHERE F.following = 1
GROUP BY [all the fields selected in F and U, or just F.userid if server settings allow]
;

【讨论】:

  • 抱歉响应缓慢...风暴杀死了互联网...刚重新上线。我尝试了您的第一个查询,这使我回到了开始的地方: WHERE F.following = 1 处的语法错误;在我尝试之前,我必须打开第二个包装并确保我完全理解它。
  • 哦,我看到 Spencer 的回答似乎发现了第一个问题(缺少子句)......看起来外部连接需要它们;如果您仍想使用第一个版本(最接近您自己的版本),您可以将ON 1= 1 添加到每个加入;但你可能会更好地接受我的第二个建议。 如果你需要做类似ON 1=1 这样的骇人听闻的事情,通常是“糟糕的形式”。
  • 我只是在板凳上标记你和斯宾塞的答案。你的返工来得更快。 0.0012 秒到他的 0.0017 秒。我觉得老了。 ;-)
【解决方案2】:

似乎缺少几个ON 子句。

我知道支持RIGHT 外连接,但为什么要这样写,而不是写成LEFT 外连接。 (我们通常保留RIGHT 加入学术界的塔楼。)

现在是时候抛弃旧式逗号语法来进行连接操作了。 (是的,它仍然支持与现有语句的向后兼容性。但是新的开发应该使用更新的JOIN 语法。)

要求F.following 的非NULL 值的条件将有效地否定连接的“外部性”,使其等效于INNER 连接。为清楚起见,我们应该将其写为内部 JOIN,或者如果我们想要外部联接,我们应该将该条件重新定位到适当的 ON 子句。

此外,最佳做法是限定所有列引用;即使它们对优化器没有歧义,它也使未来的读者更容易(因此未来的读者不必确认哪个表包含id 列),以及保护查询不抛出“模糊”如果将名为 id 的列添加到查询使用的另一个表中,则将来会出现“列”错误。

此外,在内联视图查询内的外部查询中引用来自F 的列也是无效的。我们可以使用相关子查询,但不能用作内联视图。


规范不明确。示例数据和预期输出样本将大大有助于阐明需求。


如果我们想使用返回单行、单列的相关子查询,我们可以将它们放在 SELECT 列表中...

SELECT f.*
     , u.*
     , ( SELECT COUNT(m.id)
           FROM experiences m
          WHERE m.userid = f.userid
       ) AS jobs
     , ( SELECT SUM(s.stars)
           FROM experiences s
          WHERE s.userid = f.userid
       ) AS stars
  FROM followers f
  LEFT
  JOIN users u 
    ON u.userid = f.userid
 WHERE f.following = 1     /* #1 = the user # I want the follwers of/for */
 ORDER BY ... 

我们可以使用内联视图获得相同的结果,但看起来会完全不同。

我倾向于在内联视图中进行聚合,类似于以下内容:

SELECT f.*
     , u.*
     , IFNULL(e.jobs,0) AS jobs
     , IFNULL(e.stars,0) AS stars
  FROM followers f
  LEFT
  JOIN users u
    ON u.userid = f.userid
  LEFT  
  JOIN ( SELECT ef.userid 
              , COUNT(ee.id)   AS jobs
              , SUM(ee.stars)  AS stars
           FROM followers ef
           JOIN experiences ee
             ON ee.userid = ef.userid
          WHERE ef.following = 1       /* argument */
          GROUP BY ef.userid
       ) e
   ON e.userid = f.userid
WHERE f.following = 1                  /* argument */   
ORDER BY ...

【讨论】:

  • 感谢斯宾塞的精彩回答。在打开你的包装时,我学到了很多东西。我把胜利交给了 Uueerdo,只是因为他的查询执行得更快,而且实际上我更容易理解(尽管那是次要的)。他的查询在 0.0012 秒到您的 0.0017 秒执行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-08
  • 1970-01-01
  • 1970-01-01
  • 2016-12-08
相关资源
最近更新 更多