繁体   English   中英

Oracle SQL - 这个分组有什么问题?

[英]Oracle SQL — What's wrong with this grouping?

我试图抓住一行有一些列的最大值。 通常情况下,我会使用Rank来选择rank = 1但是当我知道我只需要一个列的最大值时,这似乎毫无意义。 这是我的SQL:

SELECT
  name,
  value,
  MAX(version)
FROM
  my_table t
WHERE
  person_type = "STUDENT"
GROUP by NAME,VALUE
HAVING version = max(version)

这会在尝试运行时返回“你做错了,涉及分组错误”,即“不是GROUP BY表达式”。 如果我按类字段添加版本,则此SQL会运行,但它显然会返回所有行,而不仅仅是每个行的最大版本。

所以我的问题主要是“为什么这不起作用?” 我正在选择版本的最大值,所以我不明白为什么我需要按它分组。 我知道还有其他解决方案(分区,排名......)但我更感兴趣的是为什么这在语法上有缺陷。

编辑:更明确地使用此having子句。

假设表t中有这两行:

NAME    VALUE    VERSION
JEREMY  C        1
JEREMY  A        2

从此查询返回的内容应为:

JEREMY A 2

但如果我删除,那么我会得到:

JEREMY A 2
JEREMY C 2

通常,HAVING子句需要包含由group by生成的列。 实际上,您可以将HAVING子句视为组中的WHERE。

也就是查询:

select <whatever>
from t
group by <whatever>
having <some condition>

相当于:

select <whatever>
from (select <whatever>
      from t
      group by <whatever
     ) t
where <some condition>

如果以这种方式考虑它,你会发现max(版本)是有意义的,因为它是一个聚合值。 但是,“版本”没有意义,因为它既不是计算值也不是按列分组。

你似乎知道如何解决这个问题。 另一个评论是一些数据库(特别是mysql)会接受你的语法。 他们将“HAVING version = max(version)”视为“HAVING any(version)= max(version)”。

你试图在你的HAVING子句中使用version ,但它没有被分组。

如果您想要的只是名称,值和最大版本,则根本不需要HAVING子句。

SELECT
  name,
  value,
  MAX(version)
FROM
  my_table t
WHERE
  person_type = "STUDENT"
GROUP by NAME,VALUE

HAVING子句适用于您希望在聚合后具有“Where”子句的情况,例如

HAVING max(version) > 5

编辑:

根据您的示例数据,您按VALUE进行分组,但您真正想要做的是确定每个NAME具有MAX(VERSION)的VALUE。

为此,您需要使用WHERE EXISTS或自联接,如下所示:

select name, value, version from t 
where exists
(
  select 1 from
  (select name, max(version) version
     from t 
    group by name) s
  where s.name = t.name and s.version = t.version
)

此SQL语句失败,因为HAVING子句在GROUP BY之后运行 - 它只能对GROUP BY子句中列出的聚合或列进行操作。 如果您只按NAMEVALUE分组,则VERSION本身没有任何意义 - 它在此时为NAMEVALUE每个组合提供了许多可能的值,因此将它与MAX(version)或任何其他组合进行比较没有意义对于每个NAMEVALUE对,只有1个值的聚合。

得到你想要的另一种方式:

select *
from (select name
        , value
        , version
        , max(version) over 
            (partition by name) as max_version
    from t)
where version = max_version;

示例执行:SQL> create table t(名称varchar2(30)2,值varchar2(1)3,版本号不为null 4,约束t_pk主键(名称,版本));

Table created.

SQL> insert into t select 'JEREMY', 'C', 1 from dual
  2  union all select 'JEREMY', 'A', 2 from dual
  3  union all select 'SARAH', 'D', 2 from dual
  4  union all select 'SARAH', 'X', 1 from dual;

4 rows created.

SQL> commit;

Commit complete.

SQL> select name, value, version
  2  from (select name
  3          , value
  4          , version
  5          , max(version) over
  6              (partition by name) as max_version
  7      from t)
  8  where version = max_version;

NAME                           V    VERSION
------------------------------ - ----------
JEREMY                         A          2
SARAH                          D          2

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM