Подсчет количества дней в определенном диапазоне и с условием - PullRequest
0 голосов
/ 18 мая 2019

Моя задача - создать запрос на основе таблицы со структурой datetime_value и значением. Записи с интервалом в 1 час со значением. Я пытаюсь создать запрос, который будет возвращать количество дней в указанном периоде, сгруппированных по годам. Например, мои входные параметры: start_date, end_date и type. start_date и end_date указывают диапазон дат для поиска в тип указывает тип деления на период:

  • если число в диапазоне (1,12), то количество дней в конкретном месяце - мне удалось это сделать

  • если пусто '', то количество дней в году - также сделано

  • если (Q1, Q2, Q3, Q4), то количество дней в указанном квартале:

    -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 голосов
/ 19 мая 2019

Мне удалось сделать это совершенно по-другому, отметив период на основе входного параметра. Вот мое решение:

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
0 голосов
/ 18 мая 2019

@ cornisto, я предполагаю, что у вас есть по крайней мере одна строка в таблице на каждый день рассматриваемого периода.Чтобы уменьшить количество почасовых строк и получать по одной строке в день, вы можете сначала:

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

Чтобы получить месяц года, исходя из того, что июнь является первым месяцем каждого года:

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

NB. Чтобы скорректировать июнь до 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

Чтобы получить текущий год на основе начала года, являющегося 01-июнем каждого года:

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

Это обеспечит, что месяцы январь-май следующихгод, рассматриваются как принадлежащие предыдущему году.

Как я уже говорил в комментариях к вашему вопросу, я бы посоветовал вам выполнить всю эту логику отдельно и создать таблицу календаря / даты.С такой таблицей, которая уже есть, ваш фактический запрос (и любые другие, использующие этот июньский календарь) будут значительно упрощены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...