从多个联合表中查找行的频率

时间:2013-10-27 05:51:51

标签: mysql sql

我有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

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

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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可能会将两个查询的效率与实际数据进行比较并提供反馈。

答案 2 :(得分:0)

Mosty,你对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,因为我知道它不是很有效。您是否看到我的解决方案存在任何根本问题?