Я боролся с этой проблемой в течение нескольких дней, и теперь я обращаюсь к массам за помощью.
Моя проблема похожа, но не совсем так, как предыдущее решение на этом сайте:
PL / SQL Split, разделите дату на новые даты в соответствии с затемненными датами!
Это решение довольно логично (включите / исключите), в то время как моя проблема связана с некоторыми из них, а также слиянием.
Хотя мне нравится думать, что я имею средний / продвинутый уровень понимания SQL + PL / SQL ... Функции Oracle Analytic, по-видимому, поражают меня. Я пытался читать / учиться, но у меня мало времени.
Поскольку я не уверен в правомерности совместного использования имен таблиц (COTS), сферы деятельности и т. Д., Я собираюсь подражать моей проблеме с более неопределенным сценарием / контекстом. Надеюсь, это отразит адвокатское настроение.
К проблеме:
У меня есть таблица, в которой хранится история деятельности клиента. Клиент может приходить и уходить, поэтому в этой таблице может быть несколько строк (для каждого клиента).
CREATE TABLE activity AS
SELECT 1 AS cust_id,
TO_DATE('01-JAN-2010') AS start_dt,
TO_DATE('31-JUL-2010') AS end_dt,
'EAST' AS region
FROM DUAL
UNION
SELECT 1 AS cust_id,
TO_DATE('01-FEB-2011') AS start_dt,
TO_DATE('31-DEC-2011') AS end_dt,
'EAST' AS region
FROM DUAL;
У меня также есть таблица, в которой хранится информация об атрибутах по диапазону. Клиент может иметь несколько типов атрибутов одновременно и каждый тип несколько раз для разных интервалов времени.
CREATE TABLE attrib AS
SELECT 1 AS cust_id,
'POWER' AS atb_cd,
TO_DATE('01-JAN-2009') AS atb_start_dt,
TO_DATE('31-JAN-2010') AS atb_end_dt,
'LocalNuke' AS provider,
1.80 AS per_kwh,
0 AS per_gal
FROM DUAL
UNION
SELECT 1 AS cust_id,
'POWER' AS atb_cd,
TO_DATE('01-MAR-2010') AS atb_start_dt,
TO_DATE('31-MAR-2010') AS atb_end_dt,
'CoalGuys' AS provider,
1.60 AS per_kwh,
0 AS per_gal
FROM DUAL
UNION
SELECT 1 AS cust_id,
'POWER' AS atb_cd,
TO_DATE('01-JUN-2010') AS atb_start_dt,
TO_DATE('30-SEP-2010') AS atb_end_dt,
'LocalNuke' AS provider,
1.70 AS per_kwh,
0 AS per_gal
FROM DUAL
UNION
SELECT 1 AS cust_id,
'POWER' AS atb_cd,
TO_DATE('01-MAR-2011') AS atb_start_dt,
TO_DATE('31-DEC-9999') AS atb_end_dt,
'GeoHeat' AS provider,
1.10 AS per_kwh,
0 AS per_gal
FROM DUAL
UNION
SELECT 1 AS cust_id,
'WATER' AS atb_cd,
TO_DATE('01-MAR-2010') AS atb_start_dt,
TO_DATE('31-DEC-9999') AS atb_end_dt,
'GlacialGold' AS provider,
0 AS per_kwh,
0.60 AS per_gal
FROM DUAL;
Странности данных являются преднамеренными, я пытался сделать этот сценарий максимально реальным, не имея отношения к "реальному миру".
Результат должен ограничить периоды активности клиентов с этой фиктивной компанией и разделить все перекрывающиеся даты, чтобы сформировать график. Элементы данных должны быть объединены вместе для отчетности.
Визуально:
Cust:
|----------------------| |------------------------|
Power:
|-------------| |--| |-------| |---------------------->
Water:
|------------------------------------------------------>
Expected Result:
|----|----|--|----|----| |----|-------------------|
Решение должно быть масштабируемым, чтобы включать и другие атрибуты. В конце концов, у меня была бы эта денормализованная информация в таблице, чтобы я мог сообщать данные клиента в любой момент времени. Например, если у них была активность, сила и вода в определенный день; Я должен быть в состоянии экспортировать данные per_kwh, per_gal и активности за этот день.
Пример вывода (табличный):
CUST_ID FROM_DT THRU_DT REGION POWER_PROVIDER WATER_PROVIDER PER_KWH PER_GAL
------- ----------- ----------- ------ -------------- -------------- ------- -------
1 01-JAN-2010 31-JAN-2010 EAST LocalNuke 1.80 0
1 01-FEB-2010 28-FEB-2010 EAST 0 0
1 01-MAR-2010 31-MAR-2010 EAST CoalGuys GlacialGold 1.60 0.60
1 01-APR-2010 31-MAY-2010 EAST GlacialGold 0 0.60
1 01-JUN-2010 31-JUL-2010 EAST LocalNuke GlacialGold 1.70 0.60
1 01-FEB-2011 28-FEB-2011 EAST GlacialGold 0 0.60
1 01-MAR-2011 31-DEC-2011 EAST GeoHeat GlacialGold 1.10 0.60
Я написал что-то около 2 лет назад (когда требование было сродни просто Activity / Power), используя 2 асинхронных курсора, медленно обрабатывая (строка за строкой).
Несмотря на то, что производительность важна, главная причина, по которой я пытаюсь найти простое / массовое решение sql, - это обслуживание. Вложенность курсора if / else моего исходного решения уже сложна и будет экспоненциально хуже, по крайней мере, с еще двумя «атрибутивными» интервалами, на которые нужно разделить.
Буду признателен за любую помощь, которую может оказать любой из вас.