计算特定范围和条件下的天数

时间:2019-05-18 13:31:26

标签: mysql sql

我的问题是基于具有datetime_value和value结构的表创建查询。 记录是每1小时间隔一个值。 我要实现的目标是创建一个查询,该查询将返回指定时期内按天分组的天数。 例如,我的输入参数是:开始日期,结束日期和类型。 start_date和end_date表示要搜索的日期范围 type表示期间的划分类型:

  • 如果数字在(1,12)范围内,则是特定月份的天数-我设法做到了

  • 如果为空”,则表示一年中的天数-也已完成

  • 如果(第一季度,第二季度,第三季度,第四季度)是指定季度的天数:

    -Q1-第6、7、8个月

    -Q2-第9、10、11个月

    -Q3-第12个月以及从明年起:1、2-最大的问题!

    -Q4-第3、4、5个月

例如,当我指定时:

SET @start_date = 2017-12-20 00:00:00
SET @end_date = 2019-04-30 23:59:59
SET @type = 'Q3'

我想接收按期间分组的日期范围内的天数:

period     |   num_of_days
Q3_17_18   |   71 (dec 2017 from start_date + jan, feb 2018 = 12+31+28)
Q3_18_19   |   90 (dec 2018 + jan, feb 2019 = 31+31+28)

对于其他季度,这很容易-我只使用month(datetime_value)IN(6,7,8)等。但是他的主要问题是Q3,因为它由不同年份的月份组成。 在源表下方:

datetime_value        |  value  | 
2018-04-21 00:01:00   |   100   |
2018-04-21 00:02:00   |   400   |
2018-04-21 00:03:00   |   200   |
...
2019-02-03 00:16:00   |   100   |
2018-04-21 00:17:00   |   500   |

2 个答案:

答案 0 :(得分:0)

@cornisto,我假设您在有关期间内每天在表中至少有一行。要减少每小时的行并每天获得一行,您可以先:

GROUP BY 
    YEAR(datetime_value), MONTH(datetime_value), DAY(datetime_value)

要获取以6月为每年的第一个月的年度月份,

((((MONTH(datetime_value) + 7) - 1) % 12) + 1) AS mth_of_yr

注意:要调整到6月1日,我将添加7而不是减去5,以防止向MOD运算符显示负值。因此,假设六月通常是一年中的第6个月,但我们希望成为第1个月,则我们将结果加7,将结果13减去1,然后MOD 12将得出0,然后将结果加1以得出所需的最终结果(月)1.我习惯于使用基于日期的编号而不是基于零的编号。

要获得基于同一六月的月份的季度数字:

(((mth_of_yr - 1) DIV 3) + 1) AS qtr_of_yr

要根据每年的年初(每年6月1日)获取当前年份:

(YEAR(datetime_value) - IF(mth_of_yr > 7, 1, 0))

这将确保第二年的1月至5月属于上一年。

正如我在对问题的评论中所说,我建议您分别执行所有此逻辑并创建日历/日期表。有了这样的表格,您的实际查询(以及使用此六月日历的其他查询)将得到大大简化。

答案 1 :(得分:0)

我通过基于输入参数标记周期来设法以完全不同的方式进行操作。这是我的解决方案:

SET @start_date = '2017-01-01 00:00:00';
SET @end_date = '2019-05-30 23:59:59';
SET @period = 'Q3';

SELECT days_by_period.period AS period1, COUNT(*) AS total_days 
FROM 
    (SELECT 
        date(datetime_value) AS load_date,
        max(the_value) AS max_value,
        (CASE 
            WHEN @period LIKE 'Q%' AND MONTH(datetime_value) IN (6, 7, 8) THEN CONCAT('Q1_', RIGHT(YEAR(datetime_value), 2), '_', RIGHT(YEAR(datetime_value), 2) + 1)
            WHEN @period LIKE 'Q%' AND MONTH(datetime_value) IN (9, 10, 11) THEN CONCAT('Q2_', RIGHT(YEAR(datetime_value), 2), '_', RIGHT(YEAR(datetime_value), 2) + 1)
            WHEN @period LIKE 'Q%' AND MONTH(datetime_value) = 12 THEN CONCAT('Q3_', RIGHT(YEAR(datetime_value), 2), '_', RIGHT(YEAR(datetime_value), 2) + 1)
            WHEN @period LIKE 'Q%' AND MONTH(datetime_value) IN (1, 2) THEN CONCAT('Q3_', RIGHT(YEAR(datetime_value), 2) - 1, '_', RIGHT(YEAR(datetime_value), 2))
            WHEN @period LIKE 'Q%' AND MONTH(datetime_value) IN (3, 4, 5) THEN CONCAT('Q4_', RIGHT(YEAR(datetime_value), 2) - 1, '_', RIGHT(YEAR(datetime_value), 2))
            WHEN @period = 'YEAR' THEN CONCAT('Y_', RIGHT(YEAR(datetime_value), 2))
            ELSE CONCAT(UPPER(DATE_FORMAT(datetime_value, '%b')), '_', RIGHT(YEAR(datetime_value), 2))
        END) AS period
    FROM test_db.my_table
    WHERE datetime_value >= @start_date
    AND datetime_value <= @end_date
    GROUP BY date(datetime_value)) AS days_by_period
GROUP BY period1