Excel数组公式与MySQL等效

时间:2012-07-08 18:43:58

标签: mysql excel excel-formula

我一直在excel中使用一个非常简单的数组公式来处理一些数据集,但是当我更新计算时,它们变得太大并且绝对会破坏我的计算机性能。

excel表和MySQL数据库的布局如下:

+-Timestamp-+-value-+
| 1340816430|  .02  |
---------------------

x600,000行

这是excel公式:

{=AVERAGEIFS(B:B,A:A,"<"&A1+1000,A:A,">"&A1-1000)}

返回值的平均值,并且是Excel工作表中的第三列。有没有合理的方法让我创建一个执行类似操作的MySQL查询,并返回一个列,如果我运行excel的公式,那么该列将包含在第三列中的值?

4 个答案:

答案 0 :(得分:4)

如果您对使用Excel公式感到满意,可以加快计算速度(在我的系统上超过3000)。假设列A包含ASCENDING ORDER和B列中的时间戳值(如果尚未排序,则使用Excel排序)。
在C栏中放置= IFERROR(MATCH(A1-1000,$ A:$ A,1),1)并复制。这计算行1000时间戳的行号减去。
在D栏中输入= IFERROR(MATCH(A1 + 1000,$ A:$ A,1),1048576)并复制。这会计算行1000时间戳的行号 在列E put = AVERAGE(OFFSET(B1,C1-ROW(),0,D1-C1 + 1,1))中并向下复制。这将计算从第一行到最后一行的子集范围的平均值。

在我的系统上,这个完整计算在20秒内计算1000K行。
这种方法的缺点是它的易失性因此,无论何时进行更改,都会重新计算,但我认为您仍处于手动计算模式。

答案 1 :(得分:2)

MySQL代码:

select
  a.timestamp t1,
  avg(x.value) average_value
from
  mydata a inner join (
    select 
      timestamp, 
      value
    from mydata
    ) x
    on x.timestamp between a.timestamp - 1000 and a.timestamp + 1000
group by 
  a.timestamp
order by
  t1
;

我想,如果没有Excel开销,这将表现得更好,但我不能保证它会在600k行上快速闪电。你肯定想索引Timestamp。另请参阅我创建的SQL Fiddle

答案 2 :(得分:0)

@Peter如果您愿意,可以坚持使用Excel。只需使用http://xllarray.codeplex.com即可。您想要的公式是=AVERAGE(ARRAY.MASK((A:A>A1 + 1000)*(A:A<A1 - 1000), B:B)。我的垃圾笔记本电脑上的1MM行计算在1秒以内。请务必按Ctrl键移位 - 将其作为数组公式输入。

如果您不想构建代码,可以从我的SkyDrive中获取加载项和帮助文件:http://sdrv.ms/JtaMIV

答案 3 :(得分:0)

@Charles。啊,不。它只适用于一个公式。误读了规范。

如果您想将计算推送到C ++并将其公开为xll,那么您可以采用以下方式:

#include <algorithm>
#include <numeric>
#include "xll/xll.h"

using namespace xll;

typedef traits<XLOPER12>::xword xword;

static AddIn12 xai_windowed_average(
    L"?xll_windowed_average", XLL_FP12 XLL_FP12 XLL_FP12 XLL_DOUBLE12,
    L"WINDOWED.AVERAGE", L"Time, Value, Window"
);
_FP12* WINAPI
xll_windowed_average(_FP12* pt, _FP12* pv, double dt)
{
#pragma XLLEXPORT
static xll::FP12 a(size(*pt), 1);

double* bt0 = &pt->array[0];
double* bv0 = &pv->array[0];
double* bt = std::lower_bound(begin(*pt), end(*pt), *bt0 - dt);
double* et = std::lower_bound(begin(*pt), end(*pt), *bt0 + dt);

for (xword i = 0; i < size(*pt); ++i) {
    a[i] = (bt == et) ? 0 : std::accumulate(bv0 + (bt - bt0), bv0 + (et - bt0), 0)/(et - bt); 

    // update the window
    bt = std::lower_bound(bt, end(*pt), pt->array[i] - dt);
    et = std::lower_bound(bt, end(*pt), pt->array[i] + dt);
}

return a.get();
}