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。子查询结果(如
MIN
、SUM
等)没有聚合,所以这一定是主查询聚合后的唯一电影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;
此代码适用于代表 plus 或 minus 排名的 ranks
列的任何值。
参见 demo.
我得到了 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。子查询结果(如
MIN
、SUM
等)没有聚合,所以这一定是主查询聚合后的唯一电影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;
此代码适用于代表 plus 或 minus 排名的 ranks
列的任何值。
参见 demo.