I wonder why the subquery can't get desired result as above:
select * from quote group by code having date=max(date);
To start with:
select * from quote group by code
This query itself is not a valid one from SQL Standard perspective.
It could be, if all other columns were functionally dependent on code
, which is not the case based on table definition(code is not unique and not a primary key). Related reading: Group by clause in mySQL and postgreSQL, why the error in postgreSQL?
The query behaves kind of ANY_VALUE:
select code, ANY_VALUE(id), ANY_VALUE(`date`), ANY_VALUE(`open`)...
from quote
group by code
Regarding second part:
having date=max(date);
--
having any_value(date) = max(date) -- sidenote: it will work for single row per `code`
Here the condition in HAVING
applies after aggregation, which means the comparison is between MAX(date) per code compared to "unspecified" date.
Illustrating with example(this code will work only if only_full_group_by
is turned off):
CREATE TABLE `quote` (
`id` int(8) unsigned NOT NULL AUTO_INCREMENT,
`code` text COLLATE utf8mb4_unicode_ci,
`date` date DEFAULT NULL,
`open` double DEFAULT NULL,
PRIMARY KEY (`id`)
) ;
INSERT INTO quote(`code`, `date`, `open`)
VALUES ('a', '2020-01-01',10),
('a', '2021-01-01',20),
('a', '2022-01-01',30);
And queries:
SELECT * FROM quote;
+-----+-------+-------------+------+
| id | code | date | open |
+-----+-------+-------------+------+
| 1 | a | 2020-01-01 | 10 |
| 2 | a | 2021-01-01 | 20 |
| 3 | a | 2022-01-01 | 30 |
+-----+-------+-------------+------+
select * from quote group by code;
-- this part is unspecified, id/date/open are arbitrary
+-----+-------+-------------+------+
| id | code | date | open |
+-----+-------+-------------+------+
| 1 | a | 2020-01-01 | 1 |
+-----+-------+-------------+------+
select *, MAX(date) from quote group by code;
-- MAX(date) is stable, date is arbitrary, comparison does not make sense at this point
+-----+-------+-------------+-------+------------+
| id | code | date | open | MAX(date) |
+-----+-------+-------------+-------+------------+
| 1 | a | 2020-01-01 | 10 | 2022-01-01 |
+-----+-------+-------------+-------+------------+
select * from quote group by code having date=max(date);
-- empty
+-----+-------+-------+------+
| id | code | date | open |
+-----+-------+-------+------+
db<>fiddle demo
Saying so, in order to get all columns ranking functions MySQL 8.0+ could be used:
This section describes nonaggregate window functions that, for each row from a query, perform a calculation using rows related to that row
SELECT *
FROM (SELECT *, ROW_NUMBER() OVER(PARTITION BY `code` ORDER BY `date` DESC) AS rn
FROM `quote`) s --RANK() if `date` is not unique per code
WHERE rn = 1;
db<>fiddle demo 2