SELECT,从第 2 次算起 2 table,第 3 次 RIGHT JOIN

SELECT, 2 counts from 2nd table, RIGHT JOIN on 3rd

我正在尝试为特定用户收集 "followers"(此代码中的#1)。

我正在从 followers 做我的主要 select 因为列 following 将有用户 #1 而 followers.userid 将有执行此操作的人的用户 ID正在关注。

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

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

最后,我想加入来自用户table的followers用户记录。

我应该以 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) 有更好的方法吗?

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

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 只会给您拥有两种 "types" 经验的追随者。

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

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]
;

似乎缺少几个 ON 子句。

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

而且,放弃连接操作的 old-school 逗号语法已经过去了。 (是的,它仍然支持与现有语句的向后兼容性。但是新开发应该使用更新的 JOIN 语法。)

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

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

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


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


如果我们想使用 return 单行单列的相关子查询,我们可以将它们放在 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 ...