【发布时间】:2011-10-19 00:25:01
【问题描述】:
我已经为这个问题苦苦挣扎了几天,现在我正在向群众寻求帮助。
我的问题与此站点上的先前解决方案类似,但并不完全相同: PL/SQL Split, separate a date into new dates according to black out dates! 这个解决方案相当布尔(包括/排除),而我的问题涉及其中的一些以及合并。
虽然我认为我对 SQL+PL/SQL 有中级/高级的掌握……Oracle 分析功能显然让我大吃一惊。我一直在尝试阅读/学习,但时间不多了。
由于我不确定共享表名 (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 光标嵌套已经很难遵循,并且会成倍恶化,至少还有 2 个“属性”跨度可以拆分。
如果你们能提供任何帮助,我将不胜感激。
【问题讨论】:
-
你能发布你想要的查询的输出吗?视觉效果很有帮助,但我不确定我是否了解如何将视觉效果转换为某种表格查询结果。
-
问题已修改以包含预期的表格输出 - @JustinCave 推荐