为什么不能 select 记录具有最大日期且具有 date=max(date) 的每个代码?
Why can't select records for each code having the maximum date with having date=max(date)?
显示创建 table 结构;
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,
`high` double DEFAULT NULL,
`low` double DEFAULT NULL,
`close` double DEFAULT NULL,
`volume` bigint(15) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=17449887 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
使用内连接查找具有最大日期的每个代码的记录,例如:
SELECT q1.*
FROM quote q1
INNER JOIN
(
SELECT code, MAX(date) AS max_date
FROM quote
GROUP BY code
) q2
ON q2.code = q1.code AND
q2.max_date = q1.date;
我想知道为什么子查询不能像上面那样得到想要的结果:
select * from quote group by code having date=max(date);
请详细说明原因
@scrapy 我相信你的问题的答案与子查询与其他查询的结构之间的区别有关。子查询的工作方式是 MySQL 在外部查询 运行 之前从查询创建派生的 table,然后在 [=38] 时使用派生的 table =] 执行外部查询 (here's the documentation on derived tables for you to refer to).
您的子查询有效,因为您仅 selecting 1 列 (code
),然后您通过使用 MAX(date)
作为第二列获得聚合值最后,您在子查询的最后一行按 code
分组。
在您的第二个查询中,您正在使用 SELECT *
,然后在您尝试在 HAVING
子句中使用 MAX(date)
之前仅按 code
进行分组。此查询不起作用,因为您使用 SELECT *
selecting table 中的每一列,但您仅在 GROUP BY
子句中按 code
分组.从 MySQL v5.7 及更高版本开始,有一个名为 only_full_group_by
的东西不允许您使用 GROUP BY
运行 查询,除非您指定 [=22] 中的每一列=] 语句在你的 GROUP BY
,即:为了让你的第二个查询工作,你必须在你的 GROUP BY
子句中列出你的 table 中的每一列,因为你正在使用 SELECT *
用于您的 select 语句 (here is the documentation that talks about only_full_group_by).
最后,为了获得您正在寻找的结果集,您必须按正确的列进行分组,就像您在子查询中所做的那样。如果您在尝试获取每个 code
的最大日期的查询中使用 code
以外的任何其他内容,结果集将不相同,因为您必须按额外的列进行分组,这会抛出关闭你的结果集。
I wonder why the subquery can't get desired result as above:
select * from quote group by code having date=max(date);
开始于:
select * from quote group by code
从 SQL 标准角度来看,此查询本身无效。
可能是,如果所有其他列在功能上都依赖于 code
,但根据 table 定义则不是这种情况(代码不是唯一的,也不是主键)。相关阅读:
查询的行为类似于 ANY_VALUE:
select code, ANY_VALUE(id), ANY_VALUE(`date`), ANY_VALUE(`open`)...
from quote
group by code
关于第二部分:
having date=max(date);
--
having any_value(date) = max(date) -- sidenote: it will work for single row per `code`
此处 HAVING
中的条件在聚合后适用,这意味着比较是每个代码的 MAX(date) 与“未指定”日期之间的比较。
举例说明(此代码仅在 only_full_group_by
关闭时有效):
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);
和查询:
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 |
+-----+-------+-------+------+
这么说,为了得到所有列 ranking functions MySQL 8.0+ 可以使用:
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;
这个
select * from quote group by code having date=max(date);
有 max(date)
,这在 GROUP BY code
的上下文中是有意义的。但是 date
没有。问题是 应该比较哪 行的 date
?简单的说,大概就是'invalid'SQL.
另见“only_full_group_by”的讨论。 (较新版本的 MySQL 会将您的查询标记为无效。该标记是一种将其关闭以获取旧的、错误的评估的方法。)
这会导致子查询,例如您的子查询。还有其他一些。这是我执行 groupwise-max 的最佳方法目录:http://mysql.rjweb.org/doc.php/groupwise_max
也有很多讨论;查看我添加的标签 [groupwise-maximum]
。
其他问题:code
是股票代码吗?如果是这样,则不需要 TEXT
。通过更改为 VARCHAR(15)
,您可以获得很多性能:
删除 id
并更改为 PRIMARY KEY(code, date)
。这将扩展该子查询 显着 并且可能会改进其他一些查询。
显示创建 table 结构;
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,
`high` double DEFAULT NULL,
`low` double DEFAULT NULL,
`close` double DEFAULT NULL,
`volume` bigint(15) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=17449887 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
使用内连接查找具有最大日期的每个代码的记录,例如:
SELECT q1.*
FROM quote q1
INNER JOIN
(
SELECT code, MAX(date) AS max_date
FROM quote
GROUP BY code
) q2
ON q2.code = q1.code AND
q2.max_date = q1.date;
我想知道为什么子查询不能像上面那样得到想要的结果:
select * from quote group by code having date=max(date);
请详细说明原因
@scrapy 我相信你的问题的答案与子查询与其他查询的结构之间的区别有关。子查询的工作方式是 MySQL 在外部查询 运行 之前从查询创建派生的 table,然后在 [=38] 时使用派生的 table =] 执行外部查询 (here's the documentation on derived tables for you to refer to).
您的子查询有效,因为您仅 selecting 1 列 (code
),然后您通过使用 MAX(date)
作为第二列获得聚合值最后,您在子查询的最后一行按 code
分组。
在您的第二个查询中,您正在使用 SELECT *
,然后在您尝试在 HAVING
子句中使用 MAX(date)
之前仅按 code
进行分组。此查询不起作用,因为您使用 SELECT *
selecting table 中的每一列,但您仅在 GROUP BY
子句中按 code
分组.从 MySQL v5.7 及更高版本开始,有一个名为 only_full_group_by
的东西不允许您使用 GROUP BY
运行 查询,除非您指定 [=22] 中的每一列=] 语句在你的 GROUP BY
,即:为了让你的第二个查询工作,你必须在你的 GROUP BY
子句中列出你的 table 中的每一列,因为你正在使用 SELECT *
用于您的 select 语句 (here is the documentation that talks about only_full_group_by).
最后,为了获得您正在寻找的结果集,您必须按正确的列进行分组,就像您在子查询中所做的那样。如果您在尝试获取每个 code
的最大日期的查询中使用 code
以外的任何其他内容,结果集将不相同,因为您必须按额外的列进行分组,这会抛出关闭你的结果集。
I wonder why the subquery can't get desired result as above:
select * from quote group by code having date=max(date);
开始于:
select * from quote group by code
从 SQL 标准角度来看,此查询本身无效。
可能是,如果所有其他列在功能上都依赖于 code
,但根据 table 定义则不是这种情况(代码不是唯一的,也不是主键)。相关阅读:
查询的行为类似于 ANY_VALUE:
select code, ANY_VALUE(id), ANY_VALUE(`date`), ANY_VALUE(`open`)...
from quote
group by code
关于第二部分:
having date=max(date);
--
having any_value(date) = max(date) -- sidenote: it will work for single row per `code`
此处 HAVING
中的条件在聚合后适用,这意味着比较是每个代码的 MAX(date) 与“未指定”日期之间的比较。
举例说明(此代码仅在 only_full_group_by
关闭时有效):
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);
和查询:
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 |
+-----+-------+-------+------+
这么说,为了得到所有列 ranking functions MySQL 8.0+ 可以使用:
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;
这个
select * from quote group by code having date=max(date);
有 max(date)
,这在 GROUP BY code
的上下文中是有意义的。但是 date
没有。问题是 应该比较哪 行的 date
?简单的说,大概就是'invalid'SQL.
另见“only_full_group_by”的讨论。 (较新版本的 MySQL 会将您的查询标记为无效。该标记是一种将其关闭以获取旧的、错误的评估的方法。)
这会导致子查询,例如您的子查询。还有其他一些。这是我执行 groupwise-max 的最佳方法目录:http://mysql.rjweb.org/doc.php/groupwise_max
也有很多讨论;查看我添加的标签 [groupwise-maximum]
。
其他问题:code
是股票代码吗?如果是这样,则不需要 TEXT
。通过更改为 VARCHAR(15)
,您可以获得很多性能:
删除 id
并更改为 PRIMARY KEY(code, date)
。这将扩展该子查询 显着 并且可能会改进其他一些查询。