【问题标题】:why I have to add parentheses to make union work为什么我必须添加括号才能使工会工作
【发布时间】:2020-02-29 19:58:54
【问题描述】:

表格:

create table movies (
movie_id int primary key,
title varchar(50));

insert into movies values
(1, 'avengers'), (2, 'frozen2'), (3, 'joker');

create table users (
user_id int primary key,
name varchar(50));

insert into users values
(1, 'daniel'), (2, 'monica'), (3, 'maria'), (4, 'james');

create table movie_rating (
movie_id int,
user_id int,
rating int,
created_at date,
primary key (movie_id, user_id));

insert into movie_rating values
(1, 1, 3, '2020-01-12'),
(1, 2, 4, '2020-02-11'),
(1, 3, 2, '2020-02-12'),
(1, 4, 1, '2020-01-01'),
(2, 1, 5, '2020-02-17'),
(2, 2, 2, '2020-02-01'),
(2, 3, 2, '2020-03-01'),
(3, 1, 3, '2020-02-22'),
(3, 2, 3, '2020-02-25');

问题:编写如下 SQL 查询:

查找对电影评分最多的用户的姓名。 如果出现平局,则返回按字典顺序较小的用户名。

找出 2020 年 2 月平均评分最高的电影名称。 如果出现平局,则返回按字典顺序较小的电影名称。

查询分2行返回,以上表格的查询结果格式为:

Result table:
+--------------+
| results      |
+--------------+
| daniel       |
| frozen 2     |
+--------------+

只有当我在union 之前和之后添加括号时,我的以下解决方案才有效。

(select u.name results
from users u join movie_rating m on u.user_id = m.user_id
group by m.user_id, u.name
order by count(rating) desc, name
limit 1)
union
(select m.title results
from movies m join movie_rating r 
on m.movie_id = r.movie_id
and r.created_at between '2020-02-01' and '2020-02-29'
group by r.movie_id, m.title
order by avg(r.rating) desc, m.title
limit 1);

如果我没有括号,我会得到错误。为什么我必须使用括号才能使union 工作?

select u.name results
from users u join movie_rating m on u.user_id = m.user_id
group by m.user_id, u.name
order by count(rating) desc, name
limit 1
union
select m.title results
from movies m join movie_rating r 
on m.movie_id = r.movie_id
and r.created_at between '2020-02-01' and '2020-02-29'
group by r.movie_id, m.title
order by avg(r.rating) desc, m.title
limit 1;
ERROR:  syntax error at or near "union"
LINE 6: union
        ^

【问题讨论】:

    标签: sql postgresql sql-order-by union


    【解决方案1】:

    如果没有额外的括号,LIMIT 只允许在查询结束时使用一次,并应用于 UNION 的结果。要将 LIMIT 附加到每个 SELECT 括号是必需的。

    请查看::https://www.postgresql.org/docs/current/sql-select.html#SQL-UNION

    select_statement 是任何没有 ORDER BY、LIMIT、FOR NO KEY UPDATE、FOR UPDATE、FOR SHARE 或 FOR KEY SHARE 子句的 SELECT 语句。 (如果用括号括起来,ORDER BY 和 LIMIT 可以附加到子表达式。如果没有括号,这些子句将应用于 UNION 的结果,而不是应用于其右侧输入表达式。)

    【讨论】:

      【解决方案2】:

      https://dev.mysql.com/doc/refman/8.0/en/union.html

      要将 ORDER BY 或 LIMIT 应用于单个 SELECT,请将子句放在括住 SELECT 的括号内。

      原因是最后一个子句[group by r.movi​​e_id, m.title order by avg(r.rating) desc, m.title limit 1;] 可以申请最后一个SELECT,也可以申请UNION。括号解决了这种语法歧义。

      【讨论】:

      • 虽然答案是正确的,但最好引用 Postgres 的手册,因为问题是关于那个,而不是关于 MySQL
      • 是的,特此postgresql.org/docs/current/typeconv-union-case.html,但手册没有明确解释必须使用括号的情况。任何歧义都应该通过使用括号来解决,以在可能导致不需要的副作用的语法上强制执行语义(想要的)。复杂的 SQL 非常危险,由于难以进行自动测试,因此不推荐使用。周日好!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-19
      • 2014-07-06
      • 2021-12-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多