0

我对 SQL 有这个问题,我想不通。想象一下,我有 3 个表如下

   Names
   Nameid  name
   1       Starbucks Coffee
   2       Johns Restaurant
   3       Davids Restaurant

   user_likes
   userid   Nameid
   1        1
   2        1
   2        3

   user_visited
   userid   Nameid
   1        2

我想找到最多(喜欢+访问)的地方。我还想选择所有地方,而不仅仅是那些被喜欢或访问过的地方

我愿意:

 SELECT n.nameid, n.name , COUNT(f.nameid) AS freq
 FROM names AS n
 LEFT JOIN user_likes ON n.nameid=user_likes.nameid
 LEFT JOIN user_visited ON n.nameid=user_visited.nameid
 ORDER BY freq DESC

但它并没有给我总频率。问题是,如果一个地方既被访问又被喜欢,它只计算一次,而我希望它被计算两次。有什么建议么?

4

3 回答 3

2
SELECT n.name, t.nameid, COUNT(t.nameid) AS freq
FROM Names n
JOIN (
    SELECT nameid FROM user_likes
    UNION ALL
    SELECT nameid FROM user_visited
) t
ON n.nameid = t.nameid
GROUP BY t.nameid ORDER BY freq DESC
于 2013-10-27T06:14:05.887 回答
2

我做了一个快速测试,虽然我更喜欢 Serge 的解决方案,但这个解决方案似乎执行得更快,因为要加入的项目数量会更少:

SELECT n.nameId, n.name, coalesce(sum(likesCount), 0) totalCount FROM NAMES n
LEFT JOIN (
  SELECT nameId, count(*) likesCount FROM user_likes
  GROUP BY nameId
  UNION ALL
  SELECT nameId, count(*) visitsCount FROM user_visited
  GROUP BY nameId
) s ON n.nameId = s.nameId
GROUP BY n.nameId
ORDER BY totalCount DESC

我假设以下索引:

alter table names add index(nameid);
alter table user_likes add index(nameid);
alter table user_visited add index(nameid);

可能 OP 可以将两个查询的效率与实际数据进行比较并提供反馈。

于 2013-10-27T06:27:34.103 回答
0

大多数,你对 coalesce() 的使用给了我一个想法,我想出了这个:

  SELECT n.nameid, n.name , 
  SUM((IFNULL(user_likes.userid,0)>0)+(IFNULL(user_visited.userid,0)>0) ) AS freq
  FROM names AS n LEFT JOIN user_likes ON n.nameid=user_likes.nameid LEFT JOIN 
  user_visited ON n.nameid=user_visited.nameid ORDER BY freq DESC

由于我在这里的示例是对我的问题的简化(我必须将两个以上的表连接到主表),所以我不愿意在 SELECT 中使用 SELECT,因为我知道它不是很有效。你看到我的解决方案有什么根本问题吗?

于 2013-10-27T06:43:13.937 回答