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

时间:2012-06-20 19:21:13

标签: sql oracle group-by

我正在尝试获取具有某些列的最大值的行。通常情况下,我会使用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会运行,但它显然会返回所有行,而不仅仅是每个行的最大版本。

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

编辑:更明确地使用此条款。

假设表t中有这两行:

NAME    VALUE    VERSION
JEREMY  C        1
JEREMY  A        2

此查询返回的内容应为:

JEREMY A 2

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

JEREMY A 2
JEREMY C 2

4 个答案:

答案 0 :(得分:2)

HAVING子句通常需要包含由group生成的列。实际上,您可以将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)”。

答案 1 :(得分:1)

你试图在你的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
)

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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

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

示例执行:     SQL&GT;创建表t(名称varchar2(30)       2,值varchar2(1)       3,版本号不为空       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