Как рассчитать кварталы, которые существуют в интервале, представленном значениями даты? - PullRequest
0 голосов
/ 26 марта 2020

У меня есть следующая таблица базы данных (я использую базу данных Oracle):

ID    |        BEGINN_DATE      |      END_DATE      |    
------------------------------------------------------
114   |        11.07.2019       |     30.09.2019     |
------------------------------------------------------
115   |        01.10.2019       |     05.02.2020     |
------------------------------------------------------
116   |        15.04.2018       |     05.02.2020     |
------------------------------------------------------
117   |        01.01.2019       |     20.02.2019     |
------------------------------------------------------   
118   |        21.02.2019       |         NULL       |

Теперь мне нужен способ вычислить все первые дни кварталов, которые представлены в начале интервала, начиная с значение столбца BEGINN_DATE и значение столбца END_DATE .

Сначала мы должны показать этот кортеж в таблице выше:

ID    |        BEGINN_DATE      |      END_DATE      |    
------------------------------------------------------
114   |        11.07.2019       |     30.09.2019     |

Мне нужен SQL Результат, подобный следующему:

'01.07.2019'

(Первый день квартала представляет для меня четверть квилта, которая существует в начале интервала, начиная со значения столбца BEGINN_DATE и значения столбца END_DATE )

Во-вторых, мы должны показать это кортеж:

ID    |        BEGINN_DATE      |      END_DATE      | 
------------------------------------------------------
115   |        01.10.2019       |     05.02.2020     |

Мне нужен SQL Результат, подобный этому:

'01.10.2019'
'01.01.2020'

В-третьих, мы должны показать этот кортеж:

ID    |       BEGINN_DATE      |      END_DATE      | 
-----------------------------------------------------
116   |       15.04.2018       |     05.02.2020     |

Здесь мне нужен SQL Результат примерно так:

'01.04.2018'
'01.07.2018'
'01.10.2018'
'01.01.2019'
'01.04.2019'
'01.07.2019'
'01.10.2019'
'01.01.2020'

// РЕДАКТИРОВАТЬ: последний пример, который может включать NULL в столбце END_DATE:

ID    |        BEGINN_DATE      |      END_DATE      |    
------------------------------------------------------
117   |        03.04.2019       |     NULL           |

Здесь мне нужен SQL Результат как это (список результатов должен увеличиваться с выходом нового значения, зависит от времени выполнения оператора SQL, если начался новый квартал):

'01.04.2019'
'01.07.2019'
'01.10.2019'
'01.01.2020'

Есть ли способ решения для вычисления чего-либо например, используя предложение SQL SELECT. На данный момент я понятия не имею, как я могу начать решать эту проблему. Надеюсь, понятно, что я хочу сделать. Извините, мои знания английского языка sh не очень хороши.

Спасибо за помощь!

// РЕДАКТИРОВАТЬ

Я добавил новый столбец ACCOUNT_ID, потому что мои требования были выбраны вчера. Это моя новая таблица:

ID    |      ACCOUNT_ID     |   BEGINN_DATE      |      END_DATE      |    
-----------------------------------------------------------------------
 1    |          1          |    01.10.2019      |     30.10.2019     |
-----------------------------------------------------------------------
 2    |          2          |    01.11.2019      |     24.11.2019     |
-----------------------------------------------------------------------
 3    |          3          |    25.11.2019      |     03.01.2020     |
-----------------------------------------------------------------------
 4    |          1          |    04.01.2020      |     04.02.2020     |
-----------------------------------------------------------------------
 5    |          2          |    05.02.2020      |        NULL        |
-----------------------------------------------------------------------

Теперь я хочу получить такой результат:

ID    |      ACCOUNT_ID     |   BEGINN_DATE      |      END_DATE      |   QUARTER 
-------------------------------------------------------------------------------------
 1    |          1          |    01.10.2019      |     30.10.2019     |   01.10.2019
-------------------------------------------------------------------------------------
 2    |          2          |    01.11.2019      |     24.11.2019     |   01.10.2019
-------------------------------------------------------------------------------------
 3    |          3          |    25.11.2019      |     03.01.2020     |   01.10.2019
-------------------------------------------------------------------------------------
 3    |          3          |    25.11.2019      |     03.01.2020     |   01.01.2020
-------------------------------------------------------------------------------------
 4    |          1          |    04.01.2020      |     04.02.2020     |   01.01.2020
-------------------------------------------------------------------------------------
 5    |          2          |    05.02.2020      |        NULL        |   01.01.2020
-------------------------------------------------------------------------------------

Но, к сожалению, я получаю этот результат (для ACCOUNT_ID 3 я получаю только кортеж за квартал 01.10 .2019 и за квартал 01.01.2020 отсутствует кортеж):

ID    |      ACCOUNT_ID     |   BEGINN_DATE      |      END_DATE      |   QUARTER 
-------------------------------------------------------------------------------------
 1    |          1          |    01.10.2019      |     30.10.2019     |   01.10.2019
-------------------------------------------------------------------------------------
 2    |          2          |    01.11.2019      |     24.11.2019     |   01.10.2019
-------------------------------------------------------------------------------------
 3    |          3          |    25.11.2019      |     03.01.2020     |   01.10.2019
-------------------------------------------------------------------------------------
 4    |          1          |    04.01.2020      |     04.02.2020     |   01.01.2020
-------------------------------------------------------------------------------------
 5    |          2          |    05.02.2020      |        NULL        |   01.01.2020
-------------------------------------------------------------------------------------

Есть ли ошибка в расчете? Можно решить эту проблему?

Ответы [ 2 ]

1 голос
/ 26 марта 2020

Как насчет этого? Строки # 1 - 5 представляют примеры данных (у вас уже есть), поэтому запрос, который вам нужен, начинается со строки № 7.

  • , если beginn_date не принадлежит месяцу, в котором определенная четверть начинается, обрежьте его до q (uarter) (строка # 8)
    • предыдущее «решение» обрезало его до mm, что является 1-м днем ​​в этом месяце
  • если нет end_date, используйте функцию nvl с sysdate (строка # 12)

SQL> with test (id, beginn_date, end_date) as
  2    (select 114, date '2019-07-11', date '2019-09-30' from dual union all
  3     select 115, date '2019-10-01', date '2020-02-05' from dual union all
  4     select 116, date '2018-04-15', date '2020-02-05' from dual union all
  5     select 117, date '2019-04-03', null              from dual
  6    )
  7  select id,
  8         add_months(trunc(beginn_date, 'q'), 3 * (column_value - 1)) result
  9  from test cross join
 10       table(cast(multiset(select level from dual
 11                           connect by level <=
 12                           months_between(trunc(nvl(end_date, sysdate), 'mm'),
 13                                          trunc(beginn_date, 'mm')
 14                                         ) / 3 + 1
 15                           ) as sys.odcinumberlist))
 16  order by id, result;

        ID RESULT
---------- ----------
       114 01.07.2019
       115 01.10.2019
       115 01.01.2020
       116 01.04.2018
       116 01.07.2018
       116 01.10.2018
       116 01.01.2019
       116 01.04.2019
       116 01.07.2019
       116 01.10.2019
       116 01.01.2020
       117 01.04.2019
       117 01.07.2019
       117 01.10.2019
       117 01.01.2020

15 rows selected.

SQL>

Если вы хотите избежать указания кода * От 1029 * до Oracle (я полагаю, вам не нравится строка № 10 - table(cast(multiset(...), результат будет таким же, если вы используете

SQL> with test (id, beginn_date, end_date) as
  2    (select 114, date '2019-07-11', date '2019-09-30' from dual union all
  3     select 115, date '2019-10-01', date '2020-02-05' from dual union all
  4     select 116, date '2018-04-15', date '2020-02-05' from dual union all
  5     select 117, date '2019-04-03', null              from dual
  6    )
  7  select distinct
  8         id,
  9         add_months(trunc(beginn_date, 'q'), 3 * (level - 1)) result
 10  from test
 11  connect by level <= months_between(trunc(nvl(end_date, sysdate), 'mm'),
 12                                     trunc(beginn_date, 'mm')
 13                                    ) / 3 + 1
 14  order by id, result;

Примечание строка № 7, которая использует distinct. Если вы удалите его, вы получите ~ 300 строк, многие из которых являются дубликатами. Код, который я изначально разместил, обрабатывает это и обрабатывает лучше, чем distinct. Для небольших наборов данных вы не заметите разницу, но, безусловно, заметите, если вам придется иметь дело с большим количеством данных.

1 голос
/ 26 марта 2020

Если я прав, то вам нужен список кварталов, с которыми ваши данные в настоящее время перекрываются.

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

Быстрый и простой пример, как раз для этого вопроса, может быть следует:

CREATE TABLE calendar_quarters (
    interval_start    DATE,
    interval_cease    DATE
);

INSERT INTO calendar_quarters VALUES ('2018-01-01', '2018-04-01');
INSERT INTO calendar_quarters VALUES ('2018-04-01', '2018-07-01');
INSERT INTO calendar_quarters VALUES ('2018-07-01', '2018-10-01');
INSERT INTO calendar_quarters VALUES ('2018-10-01', '2019-01-01');
INSERT INTO calendar_quarters VALUES ('2019-01-01', '2019-04-01');
INSERT INTO calendar_quarters VALUES ('2019-04-01', '2019-07-01');
INSERT INTO calendar_quarters VALUES ('2019-07-01', '2019-10-01');
INSERT INTO calendar_quarters VALUES ('2019-10-01', '2020-01-01');
INSERT INTO calendar_quarters VALUES ('2020-01-01', '2020-04-01');
INSERT INTO calendar_quarters VALUES ('2020-04-01', '2020-07-01');
INSERT INTO calendar_quarters VALUES ('2020-07-01', '2020-10-01');
INSERT INTO calendar_quarters VALUES ('2020-10-01', '2021-01-01');

После того, как у вас есть карта интервалов, вам просто нужно посмотреть, какие интервалы перекрываются с вашими данными ...

SELECT
  calendar_quarters.interval_start
FROM
  your_table
INNER JOIN
  calendar_quarters
    ON  your_table.BEGINN_DATE < calendar_quarters.interval_cease
    AND your_table.END_DATE    > calendar_quarters.interval_start
GROUP BY
  calendar_quarters.interval_start

Обратите также внимание, что дата окончания один интервал совпадает с датой начала следующего интервала. Использует Inclusive start, exclusive end, является стандартным подходом и значительно упрощает многие аспекты математики / манипуляций с датами (ищите в Интернете дополнительную информацию) .

Это означает, что Вы можете добавить один день к своим END_DATE значениям, добавить один день к ним в запросах или использовать >= и <= в запросе.

Я настоятельно рекомендую использовать exclusive даты окончания, это действительно помогает лот .

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