MYSQL 按组加权平均
Posted
技术标签:
【中文标题】MYSQL 按组加权平均【英文标题】:MYSQL weighted average by group 【发布时间】:2016-11-08 00:30:21 【问题描述】:我有一个mysql表,结构如下
| Field | Type |
+----------------+--------------+
| Data | timestamp |
| ticker | varchar(250) |
| sentiment | double |
| numberofTweets | int(11) |
而且有 70 个不同的代码,我需要计算每个代码的加权平均值。
我正在做以下事情:
select ticker, round(sum(sentiment)/sum(numberofTweets),2) as wAverage
from sentiment
WHERE ticker = 'GBP/USD'
order by data desc
limit 288;
有没有办法在一个查询中处理所有代码?
提前谢谢!
编辑 1:
我需要为每个股票代码使用 288 条记录来进行计算,所以使用 GROUP BY clausule 将不起作用!
【问题讨论】:
整体平均还是每个股票? 对于每个代码 使用GROUP BY ticker
而不是WHERE ...
Paul 使用 'group by limit 288' 它会为每个代码选择 288 个最后的记录然后进行计算?
否 :-) - 你想要每个代码最近 288 行的平均值吗?
【参考方案1】:
为了简化您的问题,我使用下表:
CREATE TABLE `items` (
`id` MEDIUMINT(8) UNSIGNED NOT NULL,
`group_id` TINYINT(3) UNSIGNED NOT NULL,
`val` DOUBLE UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
INDEX `group_id` (`group_id`)
) ENGINE=InnoDB;
测试数据包含 100 个组,每个组平均有 1000 个项目(总共 100K 行)。
set @num_rows = 100000;
set @per_group = 1000;
set @num_groups = @num_rows div @per_group;
insert into items (id, group_id, val)
select seq as id
, floor(rand(1)*@num_groups) + 1 as group_id
, rand(2) as val
from seq_1_to_1000000
where seq <= @num_rows
;
任务:为每个group_id
获取最新288 行的val
总和。
如果没有每组 288 行的要求,那就是
select group_id, sum(val)
from items
group by group_id
但您首先需要将数据集限制为每组 288 行。搜索“mysql top n per group”,你会发现很多关于SO的相关问题。
大部分答案都会使用会话变量:
select group_id, sum(val)
from (
select i.group_id, i.val,
case when i.group_id = @group
then @rn:=@rn+1
else @rn:=1
end rn,
@group := i.group_id
from items i
cross join (select @rn := null, @group := null) init_vars
order by i.group_id, i.id desc
) t
where rn <= 288
group by group_id
order by group_id
查询时间:62 - 78 毫秒(我的客户没有显示确切的数字)。但是 - 使用此解决方案您依赖于引擎的执行顺序,这可能会在未来的版本中发生变化。
其他一些答案使用自联接:
select group_id, sum(val)
from (
select i.group_id, i.val
from items i
join items i1
on i1.group_id = i.group_id
and i1.id >= i.id
group by i.id
having count(*) <= 288
) t
group by group_id
order by group_id
但只有小团体(平均团体规模
SUBSTRING_INDEX(GROUP_CONCAT(...), ...)
也有一个“技巧”,可能需要针对大型组调整 @@group_concat_max_len
。
但我更喜欢这个:
select i.group_id, sum(i.val)
from items i
where i.id >= coalesce((
select i1.id
from items i1
where i1.group_id = i.group_id
order by i1.id desc
limit 1
offset 287
), 0)
group by i.group_id
order by i.group_id
它首先在相关子查询中找到每个组的第 288 个最高 id,并且只使用具有更高或相等 id 的行。如果一个组的行数少于 288,则将使用所有行(id >= 0)。 查询时间:78 - 94 毫秒。
根据你的问题调整它,你会得到:
select s.ticker, round(sum(sentiment)/sum(numberofTweets),2) as wAverage
from sentiment s
where s.data >= coalesce((
select s1.data
from sentiment s1
where s1.ticker = s.ticker
order by s1.data desc
limit 1
offset 287
), from_unixtime(0))
group by s.ticker
order by s.ticker
请注意,如果您按非唯一列对结果进行排序,则限制结果集的定义不明确。因此,如果两个时间戳相等,它可能会使用 289 行或更多行。最好使用 AUTO_INCREMENT PRIMARY KEY。
【讨论】:
Paul 很抱歉耽搁了这么久,今晚我会试试我和你学到的东西! tks以上是关于MYSQL 按组加权平均的主要内容,如果未能解决你的问题,请参考以下文章