SQL 视图 - 结果不同于 select

SQL view - result different than select

我得到了 table users_movies 这样的:

ID (100 records) | movie_id | ranks ( 0 or 1)
-----------------+----------+----------------
     1           |   3      |   0
     2           |   2      |   0
     3           |   2      |   1
     4           |   3      |   0
     5           |   1      |   1
     6           |   2      |   0
     etc.

我的SQL是:

SELECT
    movie_id as Movie,
    (SELECT COUNT(ranks) 
     FROM users_movies
     WHERE ranks = 1 AND movie_id = Movie) AS plus,
    (SELECT COUNT(ranks)
     FROM users_movies
     WHERE ranks = 0 AND movie_id = Movie) AS minus 
FROM 
    users_movies
GROUP BY 
    movie_id
ORDER BY 
    movie_id

结果table如预期的那样:

Movie | plus | minus
------+------+------
  1   |  5   |   2
  2   |  3   |   3
  3   |  0   |  10
  etc.

但是当我想创建视图时:

CREATE VIEW v1 
AS /*the only line I add */
    SELECT
        movie_id as Movie,
        (SELECT COUNT(ranks) 
         FROM users_movies
         WHERE ranks = 1 AND movie_id = Movie) AS plus,
        (SELECT COUNT(ranks)
         FROM users_movies
         WHERE ranks = 0 AND movie_id = Movie) AS minus 
    FROM 
        users_movies
    GROUP BY 
        movie_id
    ORDER BY 
        movie_id

结果完全不同:

Movie | plus | minus
------+------+------
  1   |  45  |  55
  2   |  45  |  55
  3   |  45  |  55
  etc.

是什么原因造成的,我该如何解决?

您的原始查询混合了似乎没有正确关联的聚合和子查询。

你可以用条件聚合来简化它:

create view v1 as
select
    movie_id,
    sum(ranks) plus,
    count(*) - sum(ranks) minus 
from users_movies
group by movie_id

这是可行的,因为 ranks 是 0 或 1,所以 sum(ranks) 给出了 rank = 1 的记录数,而 count(*) - sum(ranks) 给出了 0 的计数。

如果值不是 0 和 1,则技术有所不同:

create view v1 as
select
    movie_id,
    sum(case when ranks = 'good' then 1 else 0 end) good,
    sum(case when ranks = 'bad' then 1 else 0 end) bad 
from users_movies
group by movie_id

我不知道到底发生了什么。我看到两件事:

  • 您正在 select 子句中创建别名 Movie。您不应该在同一个 select 子句中使用此别名,因为没有必须计算 select 子句部分的顺序。
  • 在子查询中,您使用主查询中的电影 ID。子查询结果(如MINSUM等)没有聚合,所以这一定是主查询聚合后的唯一电影ID。或者这是 MySQL?然后这就变得古怪了,因为 MySQL 允许省略聚合函数。尽管如此,即使这样也不能解释不同的结果。

毕竟,你只想要这个:

CREATE VIEW v1 AS
SELECT
  movie_id,
  SUM(ranks) as plus,
  COUNT(*) - SUM(ranks) as minus
FROM users_movies
GROUP BY movie_id;

如果您为 table 添加别名并在相关子查询中使用限定的列名,那么您将获得正确的结果:

CREATE VIEW v1 AS    
SELECT
        um.movie_id as Movie,
        (SELECT COUNT(ranks) 
        FROM users_movies
        WHERE ranks = 1 and movie_id = um.movie_id) as plus,
        (SELECT COUNT(ranks)
        FROM users_movies
        WHERE ranks = 0 and movie_id = um.movie_id) as minus 
FROM users_movies um
GROUP BY um.movie_id
ORDER BY um.movie_id;  

参见demo
当然,有更好的方法可以通过条件聚合来满足您的要求,MySql 提供了简单易读的解决方案,例如:

CREATE VIEW v1 AS
SELECT
    movie_id,
    SUM(ranks = 1) plus,
    SUM(ranks = 0) minus 
FROM users_movies
GROUP BY movie_id;

此代码适用于代表 plusminus 排名的 ranks 列的任何值。
参见 demo.