Mysql 选择组中的第一个和最后一个值
我有一个MySql表,其中包含每日股票报价(开盘、高盘、低盘、收盘和成交量),我正在尝试动态地将其转换为每周数据。到目前为止,我有以下功能,适用于高、低和音量:Mysql 选择组中的第一个和最后一个值,mysql,select,group-by,Mysql,Select,Group By,我有一个MySql表,其中包含每日股票报价(开盘、高盘、低盘、收盘和成交量),我正在尝试动态地将其转换为每周数据。到目前为止,我有以下功能,适用于高、低和音量: SELECT MIN(_low), MAX(_high), AVG(_volume), CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek FROM mystockdata GROUP BY myweek ORDER BY _date; 我需要在上面的查询中选择_open的第一个实例。因此,
SELECT MIN(_low), MAX(_high), AVG(_volume),
CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
FROM mystockdata
GROUP BY myweek
ORDER BY _date;
我需要在上面的查询中选择_open的第一个实例。因此,例如,如果周一(在特定的一周中)有一个假期,而股市周二开盘,那么开盘价应该从分组为周的周二中选择。同样,收盘价应该是该周的最后一次收盘价
是否可以在MySql中选择类似FIRST()和LAST()的内容,以便将上述内容封装在单个select中,而不是使用嵌套的select查询
下面是我的表的create语句,以了解模式:
delimiter $$
CREATE TABLE `mystockdata` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`symbol_id` int(11) NOT NULL,
`_open` decimal(11,2) NOT NULL,
`_high` decimal(11,2) NOT NULL,
`_low` decimal(11,2) NOT NULL,
`_close` decimal(11,2) NOT NULL,
`_volume` bigint(20) NOT NULL,
`add_date` date NOT NULL,
PRIMARY KEY (`id`),
KEY `Symbol_Id` (`symbol_id`,`add_date`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8$$
更新:没有空值,只要有假日/周末,表中就不会包含该日期的任何记录。您可能需要使用
合并
函数来获取第一个值。但是,您需要确保那些没有数据的日子(周末和节假日)的\u open
值为空
用途如下:
SELECT MIN(_low), MAX(_high), AVG(_volume), COALESCE(_open)
CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
FROM mystockdata
GROUP BY myweek
ORDER BY _date;
对于last()值,我只能想到一个非常简单的解决方案,那就是使用GROUP\u CONCAT
然后通过字符串操作从列表中获取最后一个值。所以也许是这样的:
SELECT MIN(_low), MAX(_high), AVG(_volume), COALESCE(_open), SUBSTRING_INDEX(GROUP_CONCAT(_close), ',', -1)
CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
FROM mystockdata
GROUP BY myweek
ORDER BY _date;
注意:如果希望查询外观一致,也可以对第一项使用GROUP\u CONCAT
方法,而不是合并
SELECT MIN(_low), MAX(_high), AVG(_volume), SUBSTRING_INDEX(GROUP_CONCAT(_open), ',', 1), SUBSTRING_INDEX(GROUP_CONCAT(_close), ',', -1)
CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
FROM mystockdata
GROUP BY myweek
ORDER BY _date;
要使
GROUP\u CONCAT
正常工作,您还需要确保\u open
和\u close
字段中没有值的日期为空。如果您使用的是MySQL 8,最好的解决方案是使用现在可用的窗口函数和/或。请看一看
但是如果您使用的是较旧版本的MySQL,那么这些函数就不是了
支持。你必须使用某种变通方法来模拟它们,
例如,您可以使用聚合字符串函数,创建一组按\u date
为\u open
和按\u close
为\u close
排序的一周的所有\u open
和\u close
值,并提取该组的第一个元素:
select
min(_low),
max(_high),
avg(_volume),
concat(year(_date), "-", lpad(week(_date), 2, '0')) AS myweek,
substring_index(group_concat(cast(_open as CHAR) order by _date), ',', 1 ) as first_open,
substring_index(group_concat(cast(_close as CHAR) order by _date desc), ',', 1 ) as last_close
from
mystockdata
group by
myweek
order by
myweek
;
另一种解决方案是使用SELECT
子句中带有LIMIT 1
的子查询:
select
min(_low),
max(_high),
avg(_volume),
concat(year(_date), "-", lpad(week(_date), 2, '0')) AS myweek,
(
select _open
from mystockdata m
where concat(year(_date), "-", lpad(week(_date), 2, '0'))=myweek
order by _date
LIMIT 1
) as first_open,
(
select _close
from mystockdata m
where concat(year(_date), "-", lpad(week(_date), 2, '0'))=myweek
order by _date desc
LIMIT 1
) as last_close
from
mystockdata
group by
myweek
order by
myweek
;
请注意,我在myweek
中添加了字符串函数,以使周数始终为两位数,否则周数将无法正确排序
在将子字符串\u index与group\u concat()结合使用时也要小心:如果其中一个分组字符串包含逗号,则函数可能不会返回预期结果。基本上,您需要做的是:
SELECT PRODUCTID,
SUBSTRING_INDEX(GROUP_CONCAT(CAST(LOCATION AS CHAR) ORDER BY LOCATION DESC), ',', 1) AS LOCATION,
SUBSTRING_INDEX(GROUP_CONCAT(CAST(PRICE AS CHAR) ORDER BY LOCATION DESC), ',', 1) AS PRICE
FROM ProductLocation
GROUP BY PRODUCTID;
请注意,MySQL没有用于GROUP BY的FIRST()和LAST()聚合函数,但可以使用GROUP_CONCAT()和SUBSTRING_INDEX()函数来模拟此类FIRST()和LAST()。从MySQL 8开始,您最好使用以下函数来完成任务:
与
t1 AS(
选择低、高、量、浓度(年(\u日期)、“-”、周(\u日期))作为我的周
来自mystockdata
),
t2as(
挑选
t1.*,
第一个打开的值(_open)(按myweek ORDER按_date划分)作为第一个打开的值,
第一个_值(_close)(按myweek ORDER按_Datedesc划分)作为最后一个_close
从t1开始
)
选择最小值(低)、最大值(高)、平均值(音量)、myweek、最小值(首次打开)、最大值(上次关闭)
从t2开始
按myweek分组
按myweek订购;
正如您所知,您描述的第一个
和最后一个
在MySQL中不存在。只需一个查询就可以了,但这取决于您的表模式…更新您的帖子。谢谢,Jason。请看我上面的编辑。谢谢你,费希拉。第一种方法是使用GROUP\u CONCAT
根据需要完美地工作!美丽的。这将我的执行时间从12分钟缩短到12秒。谢谢这个查询(像OP的查询一样,顺便说一句)在MySQL的严格模式打开(或者仅仅打开)时无法工作。\u date
列在GROUP\u CONCAT
的ORDER BY
子句以及SELECT
查询的ORDER BY
子句中都是未定义的。@LukasEder我已经更新了我的答案,因为更好的解决方案是使用MySQL8中现在可用的windows函数。感谢您的评论和支持answer@LukasEder谢谢,这肯定也是一个错误。我已经更新了我的答案(当MySQL8+不可用时,它可能仍然有用),我没有使用派生表,但它应该被修复。另外,最好在周数上使用lpad,以便对周进行正确排序。现在应该可以了:)OP的问题中不存在列/表