在SQL中正确使用UNION

时间:2018-05-14 09:08:38

标签: sql sqlite

我需要计算两个不同评级平均值之间的差异,一个用于特定year_cutoff(1980)之前的电影评级,另一个用于year_cutoff之后的第二个,从两个不同的数据库查询,评级和电影。

我做的是:

我需要计算1980年以前和1980年后电影之间的平均星数差异。

首先我通过电影标题进行分组并计算每个组的平均评分。

其次,我将这些群体分为两类,1980年之前和1980年之后

最后,我试图重新计算这两组中每一组的平均值(平均值),即avgBefore和avgAfter,并计算这两个新平均值的差异

我希望有一个数字是avgBefore - avgAfter(avgB - avgA)

以下是我对代码的尝试。我的主要问题是在'之前正确插入两个条件。和'之后' 1980.我正在尝试定义像avgB和avgA这样的别名,但显然没有正确调用UNION子句。

SELECT AVG(avgB) - AVG(avgA)
FROM(
SELECT AVG(stars) as avgB
FROM Rating
JOIN Movie
ON Rating.mID = Movie.mID 
GROUP BY title
HAVING year < 1980
UNION
SELECT AVG(stars) as avgA
FROM Rating
JOIN Movie
ON Rating.mID = Movie.mID 
GROUP BY title
HAVING year > 1980
);

6 个答案:

答案 0 :(得分:1)

您希望首先获得每部电影的平均评分。从这个结果你想得到1980年以前和1980年后的平均电影评级。因此,两个步骤:每部电影聚合,然后是总聚合。

select
  avg(r.stars) as total,
  avg(case when m.year < 1980 then r.stars end) as pre1980,
  avg(case when m.year > 1980 then r.stars end) as post1980,
  avg(case when m.year < 1980 then r.stars end) -
  avg(case when m.year > 1980 then r.stars end) as diff
from
(
  select mid, avg(stars) as stars
  from rating
  group by mid
) r
join movie m on m.mid = r.mid;

(如前所述,您可能希望在前置或后置范围内包含1980部电影,而不是完整地省略它们。)

答案 1 :(得分:0)

试试这个:

SELECT AVG(avgB) - AVG(avgA)
  FROM(
       SELECT AVG(stars) as avgB
         FROM Rating
         JOIN Movie
         ON Rating.mID = Movie.mID 
        WHERE Movie.year < 1980
       GROUP BY title
      UNION
       SELECT AVG(stars) as avgA
         FROM Rating
         JOIN Movie
         ON Rating.mID = Movie.mID 
        WHERE Movie.year >= 1980
       GROUP BY title
      );

注意:我不知道您从哪里获得year值,因此您需要指定它。

更新:修正了对year的引用。

更新2 :更正了查询。

这就是我的想法。请注意,我现在无权访问数据库来验证语法,但我想它应该主要是确定:

SELECT (AVG(B.Rating_OLD) - AVG(B.Rating_NEW)) AS Rating_Diff
  FROM (
        SELECT A.title , AVG(A.stars_OLD) AS Rating_OLD ,AVG(A.stars_NEW) AS Rating_NEW
          FROM (
                SELECT title                                    , 
                       CASE 
                          WHEN Movie.year <  1980 THEN Rating.stars
                          ELSE                         0
                       END AS stars_OLD                         ,
                       CASE 
                          WHEN Movie.year >= 1980 THEN Rating.stars
                          ELSE                         0
                       END AS stars_NEW                         
                  FROM Rating
                  JOIN Movie
                   ON Rating.mID = Movie.mID
               ) A
         GROUP BY A.title 
       ) B

答案 2 :(得分:0)

如果我们遵循这种方法会怎样:

SELECT 
    (AVG(CASE WHEN year < 1980 THEN stars ELSE 0 END)-
    AVG(CASE WHEN year >= 1980 THEN stars ELSE 0 END)) AS averag
FROM Rating
JOIN Movie ON Rating.mID = Movie.mID

答案 3 :(得分:0)

在UNION上使用连接:

SELECT 
    AVG(avgB) - AVG(avgA)
FROM
(
    (
        SELECT
            AVG(stars) as avgB
        FROM 
            Rating
        JOIN 
            Movie
        ON 
            Rating.mID = Movie.mID 
        WHERE 
            year < 1980
    ) t1
    CROSS JOIN
    (
        SELECT
            AVG(stars) as avgA
        FROM 
            Rating
        JOIN 
            Movie
        ON 
            Rating.mID = Movie.mID 
        WHERE 
            year < 1980
    ) t2
);

答案 4 :(得分:0)

你做错了。在UNION中不能有两个不同的别名。您的脚本只知道别名avgB。 而不是UNION我建议您使用JOIN。

答案 5 :(得分:0)

最有效的方法是使用条件聚合:

SELECT (AVG(CASE WHEN m.year < 1980 THEN r.stars END) -
        AVG(CASE WHEN m.year >= 1980 THEN r.stars END)
       ) AS averag
FROM Rating r JOIN
     Movie m
     ON r.mID = m.mID;

尝试使用两个单独的查询只会使查询变得比它需要的更复杂。