【问题标题】:Monthly Snapshot using Date Dimension使用日期维度的月度快照
【发布时间】:2019-11-27 18:43:47
【问题描述】:

我需要将一些列带到合并表中(事实)。我有一个更改捕获表,它捕获每天记录的更改,如下所示:

CHG_TABLE: +--------+-------------------+-------- ---+-----------+------------+ |钥匙 |开始日期 |结束日期 |值 |记录类型| +--------+----- -------------+--------- --+-----------+------------+ | 1 | 2019 年 5 月 25 日 2.05 | 12/31/9999 00.00 | 800 |插入 | | 1 | 2019 年 5 月 25 日 2.05 | 2019 年 5 月 31 日 11.12 | 800 |更新 | | 1 | 2019 年 5 月 31 日 11.12 | 12/31/9999 00.00 | 900 |插入 | | 1 | 2019 年 5 月 31 日 11.12 | 2019 年 6 月 15 日 12.05 | 900 |更新 | | 1 | 2019 年 6 月 15 日 12.05 | 12/31/9999 00.00 | 1000 |插入 | | 1 | 2019 年 6 月 15 日 12.05 | 2019 年 6 月 25 日 10.20 | 1000 |更新 | | 1 | 2019 年 6 月 25 日 10.20 | 12/31/9999 00.00 | 500 |插入 | | 1 | 2019 年 6 月 25 日 10.20 | 2019 年 6 月 30 日 11.12 | 500 |更新 | | 1 | 2019 年 6 月 30 日 11.12 | 12/31/9999 00.00 | 3000 |插入 | | 1 | 2019 年 6 月 30 日 11.12 | 2019 年 7 月 15 日 1.20 | 3000 |更新 | | 1 | 2019 年 7 月 15 日 1.20 | 12/31/9999 00.00 | 7000 |插入 | +--------+-------------------+-------- ---+-----------+------------+

在第一次插入期间,End_Date 是时间的结束。当具有新 Start_Date 和 Value 的新记录添加到源时,它会被捕获为新条目,并且具有相同 Key 的先前记录会更新为 End_Date 作为新记录的 Start_Date。

DIM_DATE: +--------+-------------------+-------- ---+ |日期键 | Month_Start_Date | Month_End_Date | +--------+-----+-------------+-------- ---+ | 1 | 2019 年 6 月 1 日 | 2019 年 6 月 30 日 | | 2 | 2019 年 7 月 1 日 | 2019 年 7 月 31 日 | +--------+-------------------+-------- ---+

我正在苦苦挣扎,因为我使用的是包含 Month_Start_Date 和 Month_End_Date 的 DATE 维度。

我想从这个更改表中创建一个每月快照,如下所示:

结果: +--------+-------------------+-------- ---+-----------+------------+ |钥匙 | Month_Start_Date | Month_End_Date |Begin_Value|End_Value | +--------+-----+-------------+-------- ---+-----------+------------+ | 1 | 2019 年 6 月 1 日 | 2019 年 6 月 30 日 | 800 | 500 | | 1 | 2019 年 7 月 1 日 | 2019 年 7 月 31 日 | 500 | 3000 | +--------+-------------------+-------- ---+-----------+------------+

Begin_Value : Max(End_Date)

End_Value : Max(End_Date)

Begin_Value 应该是上个月的最新值(不是结束时间),End_Value 应该是基于 Month_End_Date 的最新值。

如何显示以上结果?

【问题讨论】:

  • 除了插入后更新前一条记录的 end_date 时,是否更新过源记录?
  • 我认为你的逻辑可能是错误的。我认为您应该寻找 End_Value = Max(Start_Date)

标签: sql oracle


【解决方案1】:

我认为你应该重新考虑一下你的逻辑。

如果CHG_TABLE 在 7 月 15 日有“更新”记录,并且以后没有更改,则该新值应为 7 月的结束值。

假设(如果)这是正确的,那么您应该完全忽略 END_DATE 列。如果可以,请将其从数据模型中删除。你不需要它。

相反,在CHG_TABLE.START_DATE 上创建一个降序索引,如下所示:

create index chg_table_n1 on chg_table (start_date desc);

然后,您应该能够像这样相当有效地创建快照:

select ct.key, 
       dd.month_start_date, 
       dd.month_end_date, 
       ( SELECT value
         FROM   chg_table ct2 
         WHERE  ct2.key = ct.key 
         AND    ct2.start_date < dd.month_start_date
         ORDER BY ct2.start_date DESC
         FETCH FIRST 1 ROW ONLY ) first_value,
       max(ct.value) keep ( dense_rank last order by ct.start_date ) last_value
from   dim_date dd
INNER JOIN chg_table ct ON ct.start_date BETWEEN dd.month_start_date and dd.month_end_date
GROUP BY ct.key, dd.month_start_date, dd.month_end_date;

希望您使用 FETCH FIRST 语法的版本 12.1 或更高版本。否则,您需要将该部分调整为 12.1 之前的等效版本。

带有测试数据的完整示例

WITH chg_table ( key, start_date, end_date, value, record_type ) AS
( 
SELECT 1,TO_DATE('5/25/2019  2.05','MM/DD/YYYY HH24.MI'),TO_DATE('12/31/9999 00.00','MM/DD/YYYY HH24.MI'), 800, 'Insert' FROM DUAL UNION ALL
SELECT 1,TO_DATE('5/25/2019  2.05','MM/DD/YYYY HH24.MI'),TO_DATE('5/31/2019  11.12','MM/DD/YYYY HH24.MI'), 800, 'Update' FROM DUAL UNION ALL
SELECT 1,TO_DATE('5/31/2019 11.12','MM/DD/YYYY HH24.MI'),TO_DATE('12/31/9999 00.00','MM/DD/YYYY HH24.MI'), 900, 'Insert' FROM DUAL UNION ALL
SELECT 1,TO_DATE('5/31/2019 11.12','MM/DD/YYYY HH24.MI'),TO_DATE('6/15/2019  12.05','MM/DD/YYYY HH24.MI'), 900, 'Update' FROM DUAL UNION ALL
SELECT 1,TO_DATE('6/15/2019 12.05','MM/DD/YYYY HH24.MI'),TO_DATE('12/31/9999 00.00','MM/DD/YYYY HH24.MI'), 1000, 'Insert' FROM DUAL UNION ALL
SELECT 1,TO_DATE('6/15/2019 12.05','MM/DD/YYYY HH24.MI'),TO_DATE('6/25/2019  10.20','MM/DD/YYYY HH24.MI'), 1000, 'Update' FROM DUAL UNION ALL
SELECT 1,TO_DATE('6/25/2019 10.20','MM/DD/YYYY HH24.MI'),TO_DATE('12/31/9999 00.00','MM/DD/YYYY HH24.MI'), 500, 'Insert' FROM DUAL UNION ALL
SELECT 1,TO_DATE('6/25/2019 10.20','MM/DD/YYYY HH24.MI'),TO_DATE('6/30/2019  11.12','MM/DD/YYYY HH24.MI'), 500, 'Update' FROM DUAL UNION ALL
SELECT 1,TO_DATE('6/30/2019 11.12','MM/DD/YYYY HH24.MI'),TO_DATE('12/31/9999 00.00','MM/DD/YYYY HH24.MI'),3000, 'Insert' FROM DUAL UNION ALL
SELECT 1,TO_DATE('6/30/2019 11.12','MM/DD/YYYY HH24.MI'),TO_DATE('7/15/2019  1.20','MM/DD/YYYY HH24.MI'), 3000, 'Update' FROM DUAL UNION ALL
SELECT 1,TO_DATE('7/15/2019  1.20','MM/DD/YYYY HH24.MI'),TO_DATE('12/31/9999 00.00','MM/DD/YYYY HH24.MI'),7000, 'Insert' FROM DUAL ),
dim_date ( datekey, month_start_date, month_end_date ) AS (
SELECT 1, DATE'2019-05-01', DATE'2019-06-01' - INTERVAL '1' SECOND FROM DUAL UNION ALL
SELECT 2, DATE'2019-06-01', DATE'2019-07-01' - INTERVAL '1' SECOND FROM DUAL UNION ALL
SELECT 3, DATE'2019-07-01', DATE'2019-08-01' - INTERVAL '1' SECOND FROM DUAL )
select ct.key, 
       dd.month_start_date, 
       dd.month_end_date, 
       ( SELECT value
         FROM   chg_table ct2 
         WHERE  ct2.key = ct.key 
         AND    ct2.start_date < dd.month_start_date
         ORDER BY ct2.start_date DESC
         FETCH FIRST 1 ROW ONLY ) first_value,
       max(ct.value) keep ( dense_rank last order by ct.start_date ) last_value
from   dim_date dd
INNER JOIN chg_table ct ON ct.start_date BETWEEN dd.month_start_date and dd.month_end_date
GROUP BY ct.key, dd.month_start_date, dd.month_end_date;
+-----+------------------+----------------+-------------+------------+
| KEY | MONTH_START_DATE | MONTH_END_DATE | FIRST_VALUE | LAST_VALUE |
+-----+------------------+----------------+-------------+------------+
|   1 | 01-MAY-19        | 31-MAY-19      |             |        900 |
|   1 | 01-JUN-19        | 30-JUN-19      |         900 |       3000 |
|   1 | 01-JUL-19        | 31-JUL-19      |        3000 |       7000 |
+-----+------------------+----------------+-------------+------------+

更新 - 没有 MAX()..KEEP() 的版本,假设存在 DIM_PERSON

select k.key, 
       dd.month_start_date, 
       dd.month_end_date, 
       ( SELECT value
         FROM   chg_table ct2 
         WHERE  ct2.key = k.key 
         AND    ct2.start_date < dd.month_start_date
         ORDER BY ct2.start_date DESC
         FETCH FIRST 1 ROW ONLY ) first_value,
       ( SELECT value
         FROM   chg_table ct2 
         WHERE  ct2.key = k.key 
         AND    ct2.start_date <= dd.month_end_date
         ORDER BY ct2.start_date DESC
         FETCH FIRST 1 ROW ONLY ) last_value
from   dim_date dd
CROSS JOIN  dim_person k
GROUP BY k.key, dd.month_start_date, dd.month_end_date;

【讨论】:

  • 谢谢@Matthew McPeak。你说得对 END_DATE 不会有用。但我认为在您的解决方案中,您只考虑了 DIM_DATE 中的 DATEKEY。我希望这个结果每个月都在 KEY 上。
  • 好的,那么您需要对我发布的第一种方法进行修改。我已经更新了我的答案。
  • 如果没有 KEEP 功能你能做到这一点吗?我想在雪花数据仓库中实现相同的解决方案,但它没有等效的 KEEP。
  • 是的,但它需要一种不同的方法,如果你有一个 KEY 的唯一值表,那么这种方法会更有效。你有这样的桌子吗?
  • 我有。这是另一个名为 DIM_PERSON 的维度,以 KEY 作为主键。
猜你喜欢
  • 1970-01-01
  • 2017-02-14
  • 1970-01-01
  • 2023-03-19
  • 2011-06-23
  • 2016-10-14
  • 1970-01-01
  • 2021-05-26
  • 1970-01-01
相关资源
最近更新 更多