【发布时间】:2016-12-19 18:01:19
【问题描述】:
之前已经问过这个问题的不同变体,但没有针对我正在寻找的用例。我想为 MySQL 表的每一行找到两个日期之间的具体工作日数,然后用该操作的结果更新每一行的列。这是 ETL 过程的一部分,如果可能的话,我希望将其保存在存储过程中。
数据
日期是 DATE 类型,我想找到特定的编号,因为如果在一周中的那一天发生记录,我有 7 个带有标志的 day 列。像这样(1 是星期一):
day_1 | day_2 | day_3 | day_4 | day_5 | day_6 | day_7
----- | ----- | ----- | ----- | ----- | ----- | -----
0 | 1 | 0 | 1 | 1 | 0 | 1
示例用例
我这样做是因为我试图找到输入数据中不可用的时间范围内的行频率(称为input)。因此,对于具有start 和end 日期值为2016-01-01 和2016-03-01 的记录,我想知道该记录仅从2016-01-01 到2016-01-31 出现的频率,包括在内。我最初尝试通过制作一个包含未来多年所有日期值的表格来做到这一点,例如:
datevalue
---------
2016-01-01
2016-01-02
...
然后在start_date 和end_date 上将input 加入该表,然后在计算每天的数量时进行汇总,如下所示:
SUM(CASE WHEN WEEKDAY(B.datevalue) + 1 = 1 THEN 1 ELSE 0 END) * day_1 +
SUM(CASE WHEN WEEKDAY(B.datevalue) + 1 = 2 THEN 1 ELSE 0 END) * day_2 +
SUM(CASE WHEN WEEKDAY(B.datevalue) + 1 = 3 THEN 1 ELSE 0 END) * day_3 +
SUM(CASE WHEN WEEKDAY(B.datevalue) + 1 = 4 THEN 1 ELSE 0 END) * day_4 +
SUM(CASE WHEN WEEKDAY(B.datevalue) + 1 = 5 THEN 1 ELSE 0 END) * day_5 +
SUM(CASE WHEN WEEKDAY(B.datevalue) + 1 = 6 THEN 1 ELSE 0 END) * day_6 +
SUM(CASE WHEN WEEKDAY(B.datevalue) + 1 = 7 THEN 1 ELSE 0 END) * day_7 AS adj_total_frequency
这在较小的数据集上运行良好,但 input 有超过 3000 万条记录,当我尝试在该程序上运行时,它运行了 36 个小时才被我杀死。
在 MySQL 中有更有效的方法吗?
【问题讨论】:
-
您可以预先计算
WEEKDAY(B.datevalue) + 1并将其存储在datevalue的表中;不知道它会加快多少。另一种方法是不给end和start加上日期,并计算出从中删除适当天数的计算。 -
预先计算
WEEKDAY() + 1将仅聚合dates表中的datevalue列的查询加快了 25%,但我不知道这种改进是否呈线性关系。你是什么意思不约会? -
哦,我不知道“不”是怎么进来的。我的意思是替代 datesub。