我有一个包含所有日期的日期维度表和另一个包含特定日期项目值的表。 例如 (a) Date_Dim 表
|Full_Date |
|-----------|
| .... |
|1-jan-2021 |
|2-Jan-2021 |
|3-jan-2021 |
| ... |
(b) Item_value 表
|P_Date | ITEM | Value |
|-----------:|:------|-------:|
|20-Dec-2020 |AA1 |9 |
|1-jan-2021 |AA1 |10 |
|1-jan-2021 |AA2 |100 |
| ... | ... | ... |
我正在尝试构建一个事实表,其中包含 date_dim 表中每个日期的 item_value 表中每个项目的最新值。即每天物品的价值。 例如
|Full_date | ITEM | Value |
|-----------:|-------:|------:|
|31-Dec-2020 |AA1 | 9 |
|31-Dec-2020 |AA2 | null |
|1-Jan-2021 |AA1 | 10 |
|1-Jan-2021 |AA2 | 100 |
|2-Jan-2021 |AA1 | 10 |
|2-Jan-2021 |AA2 | 100 |
|3-Jan-2021 |AA1 | 10 |
|3-Jan-2021 |AA2 | 100 |
|4-Jan-2021 |AA1 | 10 |
|4-Jan-2021 |AA2 | 100 |
请问如何建立这个查询? 我尝试了以下但不起作用
选择 full_date,p_date,item,value 从dim_date full_date=p_date 上的左外连接 item_value;
不确定 max(p_date) over (partition by ...) 是否有效。
谢谢
答案 0 :(得分:0)
您可以使用分区外连接然后聚合:
WITH date_dim ( full_date ) AS (
SELECT DATE '2020-12-31' + LEVEL - 1 AS full_Date
FROM DUAL
CONNECT BY DATE '2020-12-31' + LEVEL - 1 <= DATE '2021-01-04'
)
SELECT item,
full_date,
MAX( value ) KEEP ( DENSE_RANK LAST ORDER BY p_date ) AS value
FROM date_dim d
LEFT OUTER JOIN item_value i
PARTITION BY ( i.item )
ON ( d.full_date >= i.p_date )
GROUP BY item, full_date
对于样本数据:
CREATE TABLE item_value ( P_Date, ITEM, Value ) AS
SELECT DATE '2020-12-20', 'AA1', 9 FROM DUAL UNION ALL
SELECT DATE '2021-01-01', 'AA1', 10 FROM DUAL UNION ALL
SELECT DATE '2021-01-01', 'AA2', 100 FROM DUAL;
输出:
<块引用>ITEM | FULL_DATE | VALUE :--- | :-------- | ----: AA1 | 31-DEC-20 | 9 AA1 | 01-JAN-21 | 10 AA1 | 02-JAN-21 | 10 AA1 | 03-JAN-21 | 10 AA1 | 04-JAN-21 | 10 AA2 | 31-DEC-20 | null AA2 | 01-JAN-21 | 100 AA2 | 02-JAN-21 | 100 AA2 | 03-JAN-21 | 100 AA2 | 04-JAN-21 | 100
注意:不需要存储date_dim
维度表;它可以即时生成,并将减少执行(昂贵的)IO 操作从硬盘读取表的需要。
db<>fiddle here
答案 1 :(得分:0)
您可以简单地使用分析函数 ITEM
LEAD
表添加一个有效间隔
select
P_DATE,
lead(P_DATE-1,1,(select max(full_date) from date_dim)) over (partition by ITEM order by P_DATE) P_DATE_TO,
ITEM, VALUE
from item_value
;
P_DATE P_DATE_TO ITE VALUE
------------------- ------------------- --- ----------
20.12.2020 00:00:00 31.12.2020 00:00:00 AA1 9
01.01.2021 00:00:00 04.01.2021 00:00:00 AA1 10
01.01.2021 00:00:00 04.01.2021 00:00:00 AA2 100
在某些情况下,这对于您的用例来说已经足够了,因为您可以使用
在给定的VALUE
上查询特定 ITEM
的 date
select VALUE from item_value_hist h where ITEM = 'AA2'
and <query_date> BETWEEN h.P_DATE and h.P_DATE_TO
请注意,有效间隔是包含,因为我们对于 P_DATE_TO
从相邻的 P_DATE
中减去一天。您应该注意 DATE
具有时间组件。
如果您想要 ITEM per DAY 概览,您必须首先添加 缺少的早期历史,其中 VALUE
为 NULL
select
(select min(full_date) from date_dim) P_DATE, min(P_DATE)-1 P_DATE_TO, ITEM, null VALUE
from item_value
group by ITEM
having min(P_DATE) > (select min(full_date) from date_dim)
P_DATE P_DATE_TO ITE VALUE
------------------- ------------------- --- -----
31.12.2020 00:00:00 31.12.2020 00:00:00 AA2
比简单的外连接到您的维度表匹配从您的有效间隔
with item as (
select
P_DATE,
lead(P_DATE-1,1,(select max(full_date) from date_dim)) over (partition by ITEM order by P_DATE) P_DATE_TO,
ITEM, VALUE
from item_value
union all
select
/* add the missing early history without a VALUE */
(select min(full_date) from date_dim) P_DATE, min(P_DATE)-1 P_DATE_TO, ITEM, null VALUE
from item_value
group by ITEM
having min(P_DATE) > (select min(full_date) from date_dim)
)
select dt.full_date, item.ITEM, item.VALUE from item
join date_dim dt
on dt.full_date between item.P_DATE and item.P_DATE_TO
order by item.ITEM, dt.full_date
FULL_DATE ITE VALUE
------------------- --- ----------
31.12.2020 00:00:00 AA1 9
01.01.2021 00:00:00 AA1 10
02.01.2021 00:00:00 AA1 10
03.01.2021 00:00:00 AA1 10
04.01.2021 00:00:00 AA1 10
31.12.2020 00:00:00 AA2
01.01.2021 00:00:00 AA2 100
02.01.2021 00:00:00 AA2 100
03.01.2021 00:00:00 AA2 100
04.01.2021 00:00:00 AA2 100
答案 2 :(得分:0)
两步:
FROM
获取 OUTER APPLY
子句中的值,或使用 SELECT
使用子查询获取 FETCH FIRST ROW ONLY
子句中的值。查询:
select
d.full_date,
i.item,
(
select iv.value
from Item_value iv
where iv.item = i.item
and iv.p_date <= d.full_date
order by iv.p_date desc
fetch first row only
) as value
from dim_date d
cross join (select distinct item from item_value) i
order by d.full_date, i.item;
答案 3 :(得分:0)
您可以使用 cross join
后跟 left join
以引入现有值来生成日期和项目的完整列表。然后您可以使用 last_value()
或 lag()
来填充值:
select d.p_date, i.item,
coalesce(v.value,
lag(v.value ignore nulls) over (partition by i.item order by d.p_date)
) as value
from date_dim d cross join
(select distinct iv.item from item_value iv) i left join
item_value iv
on iv.p_date = d.p_date and iv.item = i.item;
您也可以使用 join
通过向值表添加“结束”日期来执行此操作:
select d.p_date, i.item,
coalesce(v.value,
lag(v.value ignore nulls) over (partition by i.item order by d.p_date)
) as value
from date_dim d cross join
(select distinct iv.item from item_value iv) i left join
(select iv.*,
lead(p_date) over (partition by item order by p_date) as next_p_date
from item_value iv
) iv
on i.item = iv.item and
d.p_date >= iv.p_date and
(iv.next_p_date is null or d.p_date < iv.next_p_date);