我有一个MySql表,包含每日股票报价(开盘价,最高价,最低价,收盘价和成交量),我试图将其转换为每周数据。到目前为止,我有以下功能,适用于高,低和音量:
SELECT MIN(_low), MAX(_high), AVG(_volume),
CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
FROM mystockdata
GROUP BY myweek
ORDER BY _date;
我需要在上面的查询中选择_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$$
更新:没有空值,无论哪里有假期/周末,该表都没有该日期的任何记录。
答案 0 :(得分:32)
如果您使用的是MySQL 8,那么首选的解决方案将使用现在可用的窗口函数FIRST_VALUE()和/或LAST_VALUE()。请查看Lukas Eder's answer。
但是如果您使用的是旧版本的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
;
另一种解决方案是在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
;
请注意我已将LPAD()字符串功能添加到myweek
,以使周数始终为两位数字,否则将无法正确订购周数。
将substring_index与group_concat()结合使用时也要小心:如果其中一个分组的字符串包含逗号,则该函数可能不会返回预期的结果。
答案 1 :(得分:2)
从MySQL 8开始,您最好使用window functions来完成任务:
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;
答案 2 :(得分:1)
您可能需要COALESCE
函数才能获得第一个值。但是,在没有数据的情况下,您需要确保没有数据的日期(周末和假日)对_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()值,我只能想到一个非常hacky的解决方案,即使用GROUP_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_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_CONCAT
正常工作,您还需要确保_open
和_close
字段中没有值的日期为空。
答案 3 :(得分:-1)
基本上,你需要做什么:
将它们放在一起,您可以使用以下查询:
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()。