使用UNION和子查询在计数查询中显示0,不允许联接

时间:2018-11-07 12:54:19

标签: sql oracle

我有2张桌子(电影和手表)。

enter image description here

我想知道有多少人正在观看哪些电影。

我这样做了:

SELECT movieID, count(persID) FROM watch GROUP BY persID;

这基本上给了我我想要的东西。唯一的问题是,没有任何人观看的电影不会以0观众的身份显示在我的结果表中,但它们被排除在外了。

我想通过两种不同的方式来实现这一目标。使用UNION,另一种方式使用子查询。

4 个答案:

答案 0 :(得分:1)

因此,您可以获得正在观看的电影列表和计数器-左将其加入所有电影列表:

SELECT * FROM
  Movies m
  LEFT JOIN
  (select movieID, count(persID) as countwatch from watch group by persID) w
  ON m.movieid = w.movieid

左加入意味着您可以获取所有电影,并且仅与正在观看的电影相关联。如果未观看电影,则其countwatch列将为

如果要将空值转换为0,请使用COALESCE:

SELECT m.*, COALESCE(w.countwatch, 0) as countwatch FROM
  Movies m
  LEFT JOIN
  (select movieID, count(persID) as countwatch from watch group by persID) w
  ON m.movieid = w.movieid

我们可以使用很多方法来执行此查询,但是我特别选择了这种方式,因为它基于您已经知道的内容,并概述了如何在子级别上对数据进行分组和汇总,然后将其连接到外层更多数据

它还很有用,因为您可能想在销售表中添加一些额外的数据,例如以了解正在观看的电影是收入最高的电影。如果选择Salman的路线(在此情况下正确),则在添加更多表时会遇到统计信息问题,因为行数的乘积会超出您的预期。通过将销售和观看分组,例如,您可以将它们连接到主表,而不会导致行重复(也称为笛卡尔乘积)。因此,对于这种性质的查询,我倾向于建议在子查询中进行分组和聚合,然后再加入其他表,以保持主表(电影)与子查询的输出(例如观看,销售,演员人数)之间的1:1关系。 ,等等)包含与主要电影相关但彼此之间不一定相关的数据

答案 1 :(得分:0)

尝试这样做

select movie.title, count(watch.persID) 
from movies left outer join watch on movies.id = watch.movieID 
group by movieID;

我认为它可以工作

答案 2 :(得分:0)

由于您坚持使用UNION和子查询,因此下面的答案将同时使用:

SELECT movieID, COUNT(*) AS watchCount
FROM watch
GROUP BY movieID
UNION
SELECT movieID, 0
FROM movies
WHERE movieID NOT IN (
    SELECT movieID
    FROM watch
    WHERE movieID IS NOT NULL
)

答案 3 :(得分:0)

仅使用UNION:

SELECT movieID, COUNT(*) -1 AS watchCount -- subtract the movie row
FROM
 ( 
    SELECT movieID -- multiple rows per watched movie
    FROM watch
    UNION ALL
    SELECT movieID -- exactly one row per movie
    FROM movies
 )

或(如果要监视的行很多,可能会更快)

SELECT movieID, max(cnt)
FROM
 ( 
    SELECT movieID, count(*) as cnt
    FROM watch
    GROUP BY movieID
    UNION ALL
    SELECT movieID, 0
    FROM movies
 )
GROUP BY movieID