Excel数组公式与MySQL等效

我在Excel中使用了一个非常简单的数组公式来计算一些数据集,但是它们变得太大,并且无论何时更新计算,都会破坏我的计算机性能。

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

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

x600,000行

这是Excel的公式:

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

这将返回值的平均值,并且是Excel表单中的第三列。 有没有什么合理的方式来创build一个MySQL查询执行类似的操作,并返回一个列的值将会在第三列我运行Excel的公式?

如果你喜欢使用Excel公式,你可以加快这个计算(在我的系统上超过3000)。 假设列A包含在“升序排列”和“列B”中的时间戳(如果尚未sorting,则使用Excelsorting)。
在列C put = IFERROR(MATCH(A1-1000,$ A:$ A,1),1)并拷贝下来。 这将计算行1000时间戳的行数减去。
在列D中put = IFERROR(MATCH(A1 + 1000,$ A:$ A,1),1048576)并复制下来。 这更多地计算行1000时间戳的行号。
在E列中put = AVERAGE(OFFSET(B1,C1-ROW(),0,D1-C1 + 1,1))并拷贝下来。 这将计算从第一行到最后一行的子范围的平均值。

在我的系统上,这个完整的计算在20秒内1000K行。
这种方法的缺点是它的volatile会在你做出改变时重新计算,但是我认为你仍然处于Manual计算模式。

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的开销,这将performance得更好,但我不能保证它将闪电在60万行。 你一定会想索引Timestamp 。 另请参阅我创build的SQL小提琴 。

@彼得你可以坚持使用Excel,如果你想。 只需使用http://xllarray.codeplex.com 。 你需要的公式是=AVERAGE(ARRAY.MASK((A:A>A1 + 1000)*(A:A<A1 - 1000), B:B) 。确定按Ctrl-Shift-input数组公式。

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

@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(); }