Zis*_*han 23 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;
Run Code Online (Sandbox Code Playgroud)
我需要在上面的查询中选择_open的第一个实例.因此,例如,如果星期一(在特定的一周)有假期并且星期二开放股票市场,则应该从星期二开始选择_开值,该星期二分组为其周.同样,close值应该是该周的最后一个_close.
是否可以在MySql中选择类似FIRST()和LAST()的内容,以便上述内容可以包含在单个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$$
Run Code Online (Sandbox Code Playgroud)
更新:没有空值,无论何处有假期/周末,该表都没有该日期的任何记录.
fth*_*lla 36
如果您使用的是MySQL 8,那么首选的解决方案是使用窗口函数FIRST_VALUE()和/或LAST_VALUE(),它们现在可用.请看看Lukas Eder的答案.
但是,如果您使用的是旧版本的MySQL,则不支持这些功能.您可以选择使用某种解决方法来模拟它们,例如你可以利用聚集串功能的GROUP_CONCAT()创建一组所有_open,并_close通过下令一周的值_date的_open和_date desc为_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
;
Run Code Online (Sandbox Code Playgroud)
另一个解决方案是LIMIT 1在SELECT子句中使用子查询:
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
;
Run Code Online (Sandbox Code Playgroud)
请注意我添加了LPAD()字符串函数myweek,以使周数始终为两位数,否则将无法正确订购周数.
将substring_index与group_concat()结合使用时也要小心:如果其中一个分组字符串包含逗号,则该函数可能不会返回预期结果.
从 MySQL 8 开始,您最好使用窗口函数来完成任务:
WITH
t1 AS (
SELECT _low, _high, _volume, CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
FROM mystockdata
),
t2 AS (
SELECT
t1.*,
FIRST_VALUE(_open) OVER (PARTITION BY myweek ORDER BY _date) AS first_open,
FIRST_VALUE(_close) OVER (PARTITION BY myweek ORDER BY _date DESC) AS last_close
FROM t1
)
SELECT MIN(_low), MAX(_high), AVG(_volume), myweek, MIN(first_open), MAX(last_close)
FROM t2
GROUP BY myweek
ORDER BY myweek;
Run Code Online (Sandbox Code Playgroud)