Reputation: 5433
I am trying to grab a row that has the max of some column. Normally I'd use Rank for this and just select rank = 1 but that seems pointless when I know I just need the max of a column. Here is my SQL:
SELECT
name,
value,
MAX(version)
FROM
my_table t
WHERE
person_type = "STUDENT"
GROUP by NAME,VALUE
HAVING version = max(version)
This returns the "You've done something wrong involving grouping error" i.e. "not a GROUP BY expression" when trying to run. If I add version to the group by field, this SQL runs, but it obviously returns all rows instead of just the max version of each.
So my question is mostly "Why doesn't this work?" I am selecting the max of version so I don't see why I need to group by it. I know there are other solutions (partition over, rank ...) but I am more interested in why this in particular is flawed syntactically.
EDIT: More explicit about the use of this having clause.
Let's say there are these two rows in table t:
NAME VALUE VERSION
JEREMY C 1
JEREMY A 2
What is returned from this query should be:
JEREMY A 2
But if I remove having then I would get:
JEREMY A 2
JEREMY C 2
Upvotes: 1
Views: 309
Reputation: 18430
Another way of getting what you want:
select *
from (select name
, value
, version
, max(version) over
(partition by name) as max_version
from t)
where version = max_version;
Sample execution: SQL> create table t (name varchar2(30) 2 , value varchar2(1) 3 , version number not null 4 , constraint t_pk primary key (name, version));
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
Upvotes: 0
Reputation: 6819
You're trying to use version
in your HAVING clause, but it's not being grouped by.
If all you want is the name, value and max version, you don't need the HAVING
clause at all.
SELECT
name,
value,
MAX(version)
FROM
my_table t
WHERE
person_type = "STUDENT"
GROUP by NAME,VALUE
The HAVING clause is for when you want to have a "Where" clause after aggregation, like
HAVING max(version) > 5
EDIT:
Based on your sample data, you're grouping by VALUE but what you really want to do is identify the VALUE that has the MAX(VERSION) for each NAME.
To do this, you need to use a WHERE EXISTS or self join, like so:
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
)
Upvotes: 1
Reputation: 231871
This SQL statement fails because the HAVING
clause runs after the GROUP BY
-- it can only operate on either aggregates or columns that are listed in the GROUP BY
clause. If you have only grouped by NAME
and VALUE
, VERSION
alone has no meaning-- it has many possible values for every combination of NAME
and VALUE
at that point so it doesn't make sense to compare it to MAX(version)
or any other aggregate which has exactly 1 value for every NAME
and VALUE
pair.
Upvotes: 1
Reputation: 1271181
The HAVING clause, in general, needs to contain columns that are produced by the group by. In fact, you can think of the HAVING clause as a WHERE on the group by.
That is, the query:
select <whatever>
from t
group by <whatever>
having <some condition>
is equivalent to:
select <whatever>
from (select <whatever>
from t
group by <whatever
) t
where <some condition>
If you think about it this way, you'll realize that max(version) makes sense because it is an aggregated value. However, "version" does not make sense, since it is neither a calculated value nor a group by column.
You seem to know how to fix this. The one other comment is that some databases (notably mysql) would accept your syntax. They treat "HAVING version = max(version)" as "HAVING any(version) = max(version)".
Upvotes: 2