SQL - 对多列的所有时间、30 天和 90 天的数据进行汇总

urw*_*CFC 5 mysql sql pivot group-by query-optimization

背景:

我有看起来像这样的数据

date        src    subsrc   subsubsrc   param1  param2
2020-02-01  src1    ksjd    dfd8        47      31    
2020-02-02  src1    djsk    zmnc        44      95    
2020-02-03  src2    skdj    awes        92      100   
2020-02-04  src2    mxsf    kajs        80      2     
2020-02-05  src3    skdj    asio        46      53    
2020-02-06  src3    dekl    jdqo        19      18    
2020-02-07  src3    dskl    dqqq        69      18    
2020-02-08  src4    sqip    riow        64      46    
2020-02-09  src5    ss01    qwep        34      34    
Run Code Online (Sandbox Code Playgroud)

我正在尝试汇总过去 30 天和过去 90 天的所有时间(无滚动总和)

所以我的最终数据看起来像这样:

src     subsrc  subsubsrc   p1_all  p1_30   p1_90   p2_all  p2_30   p2_90
src1    ksjd    dfd8        7       1       7       98      7        98
src1    djsk    zmnc        0       0       0       0       0         0
src2    skdj    awes        12      12      12      4       4         4
src2    mxsf    kajs        6       6       6       31      31       31
src3    skdj    asio        0       0       0       0       0         0
src3    dekl    jdqo        20      20      20      17      17        17
src3    dskl    dqqq        3       3       3       4       4         4
src4    sqip    qwep        0       0       0       0       0         0
src5    ss01    qwes        15      15      15      2       2         2
Run Code Online (Sandbox Code Playgroud)

关于数据:

  • 这只是虚拟数据,因此是不正确的。
  • 我的数据中有数万行。
  • 有十几个 src 列构成了表的键。
  • 有十几个参数列我必须对 30 和 90 以及所有时间求和。
  • param 列中也有空值。
  • 同一天和 src 列也可能有多行。
  • 每天都在添加新数据,并且可能每天都会运行查询以获取最新的 30、90 次所有时间数据。

我试过的:

这是我想出的:

SELECT src, subsubsrc, subsubsrc,
SUM(param1) as param1_all,
SUM(CASE WHEN DATE_DIFF(CURRENT_DATE,date,day) <= 30 THEN param1 END) as param1_30,
SUM(CASE WHEN DATE_DIFF(CURRENT_DATE,date,day) <= 90 THEN param1 END) as param1_90,
SUM(param2) as param2_all,
SUM(CASE WHEN DATE_DIFF(CURRENT_DATE,date,day) <= 30 THEN param2 END) as param2_30,
SUM(CASE WHEN DATE_DIFF(CURRENT_DATE,date,day) <= 90 THEN param2 END) as param2_90,
FROM `MY_TABLE`
GROUP BY src
ORDER BY src
Run Code Online (Sandbox Code Playgroud)

这实际上有效,但我可以预测对于多个来源甚至更多参数列,此查询将花费多长时间。

我一直在尝试一种叫做“过滤聚合函数(或手动数据透视) ”的东西在这里解释。但我无法理解/为我的案例实施它。

此外,我查看了数十个答案,其中大多数是每天的总和,或者是这种基本计算的复杂情况。也许我没有正确搜索它。

如您所见,我是 SQL 新手,非常感谢您的帮助。

Sta*_*nko 0

我建议您使用 3 个不同的查询:

  1. 所有时间的总和
  2. 30天总和
  3. 90 天的总和

因为当您尝试执行全合一查询时,您最终会进行全表扫描(顺便说一句,MySQL 中CASE-WHEN-END有紧凑形式)。IF()这是非常不理想的。

如果您将其拆分为 3 个不同的查询并向该date列添加索引,那么它不会对第二个和第三个查询进行全扫描。仅适用于第一个查询,可以单独优化(例如通过缓存)。

还有这种方法:DATE_DIFF(CURRENT_DATE,date,day) <= 90

应更改为:(date >= 'date-90-days-ago'其中'date-90-days-ago'是固定日期)

因此,您不必计算每行 2 个日期的差异。您只需计算 2 个日期:30 天前和 90 天前,并将所有其他日期与这两个日期进行比较。这种方法将受益于date列索引。