Как присоединить таблицy dim_date для появления first_of_month_date в общей таблице
У меня есть 2 таблицы, для пустых строк нужно добавить верхнее значение. Проблема в том, что после объединения с таблицей dim_date даты пропущенных дат в общем запросе не отображаются. Например, именно для опреленного id я получила строки, но если без, я не могу. https://stackoverflow.com/questions/75863208/how-to-join-dim-date-table-for-appears-first-of-month-date
select first_day_of_month, last_value(c_loan_agreement_id) IGNORE NULLS OVER (ORDER BY first_day_of_month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) c_loan_agreement_id from business_core.dim_date dd
left join business_core.fact_loan_agreement fla on date_trunc('month',fla.date_term_date) = dd.first_day_of_month and dd.first_day_of_month <= '2023-12-01' and dd.first_day_of_month>= '2022-12-01' --and fla.c_loan_agreement_id= 'ALB000ab242-d005-4dc0-bf05-58dda00658a7'
where dd.first_day_of_month <= '2023-12-01' and dd.first_day_of_month>= '2022-12-01'
group by c_loan_agreement_id, first_day_of_month ```
etoo adoptivnoe query s uchetom commentarija
select first_day_of_month, date_trunc('month',nextdate::date) as nextdate , last_value(c_loan_agreement_id) IGNORE NULLS OVER (ORDER BY first_day_of_month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) c_loan_agreement_id from business_core.dim_date dd
left join ( select c_loan_agreement_id, date_trunc('month', frr.repayment_date)::date as BOP, date_trunc('month',lead(frr.repayment_date,1)over(partition by c_loan_agreement_id order by frr.repayment_date)) as nextdate from business_core.fact_receivable_repayment frr group by c_loan_agreement_id,bop, repayment_date ) frr on frr.bop <= dd.first_day_of_month and nextdate>dd.first_day_of_month
where dd.first_day_of_month <= current_date and dd.first_day_of_month>= '2022-12-01'
group by c_loan_agreement_id, first_day_of_month, nextdate; ```
[![введите сюда описание изображения][1]][1]
[![введите сюда описание изображения][2]][2]
[1]: https://i.stack.imgur.com/iRGje.png
[2]: https://i.stack.imgur.com/UjnX5.png
Ответы (1 шт):
Посмотрите пример соединения таблицы с календарем. Календарь создан "на ходу", рекурсивным перебором дат от мин до макс даты.
Для соединения другой таблицы с календарем, в целевой таблице выбираем текущую и следующую дату lead(EventDate,1,EventDate)over(partition by id order by EventDate) nextdate.
Соединение с календарем должно быть от текущей даты до следующей. Т.е. соединяем текущую строку и календарь, поэтому значения текущей строки наследуются и в добавляемые (соединяемые) строки.
UPD. Добавлю тестовые данные, чтобы были разные Id. Запрос отработает правильно при разных Id, в том числе когда диапазоны пересекается.
WITH src AS (
SELECT id,cast(EventDate as date) EventDate, value
FROM( VALUES
(4, '2022-12-30', 100.0)
,(4, '2023-01-04', 200.0)
,(4, '2023-01-07', 300)
,(5, '2023-01-04', 250)
,(5, '2023-01-07', 350)
) t (id,EventDate,Value)
)
,dim_date as (
select 0 n,dateadd(d,0,(select min(EventDate) from src)) day_of_month
, (select datediff(d,min(EventDate),max(EventDate)) from src) maxn
union all
select n+1,dateadd(d,1,day_of_month),maxn from dim_date where n<maxn
)
,data as(
select id,EventDate,value
,lead(EventDate,1,EventDate)over(partition by id order by EventDate) nextdate
from src
)
SELECT t.id
,case when coalesce(n,0)=0 then EventDate
else m.day_of_month
end EventDate
,t.value
,m.n,nextdate,EventDate EventDate2 ,m.day_of_month cdate
FROM data t
left JOIN dim_date m on t.EventDate<=m.day_of_month and t.nextdate>m.day_of_month
order by id,EventDate
option (maxrecursion 500)
Пример результата запроса
| ID | EventDate | value | n | nextdate | EventDate2 | day_of_month |
|---|---|---|---|---|---|---|
| 4 | 2022-12-30 | 100.0 | 0 | 2023-01-04 | 2022-12-30 | 2022-12-30 |
| 4 | 2022-12-31 | 100.0 | 1 | 2023-01-04 | 2022-12-30 | 2022-12-31 |
| 4 | 2023-01-01 | 100.0 | 2 | 2023-01-04 | 2022-12-30 | 2023-01-01 |
| 4 | 2023-01-02 | 100.0 | 3 | 2023-01-04 | 2022-12-30 | 2023-01-02 |
| 4 | 2023-01-03 | 100.0 | 4 | 2023-01-04 | 2022-12-30 | 2023-01-03 |
| 4 | 2023-01-04 | 200.0 | 5 | 2023-01-07 | 2023-01-04 | 2023-01-04 |
| 4 | 2023-01-05 | 200.0 | 6 | 2023-01-07 | 2023-01-04 | 2023-01-05 |
| 4 | 2023-01-06 | 200.0 | 7 | 2023-01-07 | 2023-01-04 | 2023-01-06 |
| 4 | 2023-01-07 | 300.0 | null | 2023-01-07 | 2023-01-07 | null |
| 5 | 2023-01-04 | 250.0 | 5 | 2023-01-07 | 2023-01-04 | 2023-01-04 |
| 5 | 2023-01-05 | 250.0 | 6 | 2023-01-07 | 2023-01-04 | 2023-01-05 |
| 5 | 2023-01-06 | 250.0 | 7 | 2023-01-07 | 2023-01-04 | 2023-01-06 |
| 5 | 2023-01-07 | 350.0 | null | 2023-01-07 | 2023-01-07 | null |
Возможно, Вам больше подойдет такой вариант, когда нужны остатки не по дням, а начало месяца:
WITH src AS (
SELECT id,cast(EventDate as date) EventDate, value
FROM( VALUES
(4, '2022-12-30', 100.0)
,(4, '2023-01-04', 200.0)
,(4, '2023-01-07', 300)
,(4, '2023-02-08', 201)
,(5, '2023-01-04', 250)
,(5, '2023-03-07', 350)
,(5, '2023-04-05', 350)
) t (id,EventDate,Value)
)
,dim_date as (
select 0 n,datefromparts((select year(min(EventDate)) from src)
,(select month(min(EventDate)) from src)
,1) first_day_of_month
, (select eomonth(max(EventDate)) from src) maxDate
union all
select n+1,dateadd(mm,1,first_day_of_month),maxDate from dim_date
where dateadd(m,1,first_day_of_month)<=maxDate
)
,data as(
select id,EventDate,value
,lead(EventDate,1,EventDate)over(partition by id order by EventDate) nextdate
from src
)
--select * from dim_date
SELECT t.id
,case when EventDate>first_day_of_month then EventDate
else m.first_day_of_month
end EventDate
,t.value
,m.n,nextdate,EventDate EventDate0 ,m.first_day_of_month first_day
FROM data t
left JOIN dim_date m
on
( first_day_of_month between eventdate and nextdate )
or
( month(t.EventDate)=month(first_day_of_month) )
order by id,EventDate
option (maxrecursion 500)
Результат запроса на этих тестовых данных
| id | EventDate | value | n | nextdate | EventDate0 | first_day |
|---|---|---|---|---|---|---|
| 4 | 2022-12-30 | 100.0 | 0 | 2023-01-04 | 2022-12-30 | 2022-12-01 |
| 4 | 2023-01-01 | 100.0 | 1 | 2023-01-04 | 2022-12-30 | 2023-01-01 |
| 4 | 2023-01-04 | 200.0 | 1 | 2023-01-07 | 2023-01-04 | 2023-01-01 |
| 4 | 2023-01-07 | 300.0 | 1 | 2023-02-08 | 2023-01-07 | 2023-01-01 |
| 4 | 2023-02-01 | 300.0 | 2 | 2023-02-08 | 2023-01-07 | 2023-02-01 |
| 4 | 2023-02-08 | 201.0 | 2 | 2023-02-08 | 2023-02-08 | 2023-02-01 |
| 5 | 2023-01-04 | 250.0 | 1 | 2023-03-07 | 2023-01-04 | 2023-01-01 |
| 5 | 2023-02-01 | 250.0 | 2 | 2023-03-07 | 2023-01-04 | 2023-02-01 |
| 5 | 2023-03-01 | 250.0 | 3 | 2023-03-07 | 2023-01-04 | 2023-03-01 |
| 5 | 2023-03-07 | 350.0 | 3 | 2023-04-05 | 2023-03-07 | 2023-03-01 |
| 5 | 2023-04-01 | 350.0 | 4 | 2023-04-05 | 2023-03-07 | 2023-04-01 |
| 5 | 2023-04-05 | 350.0 | 4 | 2023-04-05 | 2023-04-05 | 2023-04-01 |
Другой пример, для случая, когда последняя добавленная запись должна быть началом следующего месяца от последней записи в таблице.
WITH src AS (
SELECT id,cast(EventDate as date) EventDate, value
FROM( VALUES
(4, '2022-12-30', 100.0)
,(4, '2023-01-04', 200.0)
,(4, '2023-01-07', 300)
,(4, '2023-02-08', 201)
,(5, '2023-01-04', 250)
,(5, '2023-03-31', 350)
,(5, '2023-04-01', 360)
) t (id,EventDate,Value)
)
,dim_date as (
select 0 n,datefromparts((select year(min(EventDate)) from src)
,(select month(min(EventDate)) from src)
,1) first_day_of_month
, dateadd(d,1,(select eomonth(max(EventDate)) from src)) maxDate
union all
select n+1,dateadd(mm,1,first_day_of_month),maxDate from dim_date
where dateadd(m,1,first_day_of_month)<=maxDate
)
,data as(
select id,EventDate,value
,lead(EventDate)over(partition by id order by EventDate) nextdate
from src
)
SELECT t.id
,case when EventDate>first_day_of_month then EventDate
else m.first_day_of_month
end EventDate
,t.value
,m.n,nextdate,EventDate EventDate0 ,m.first_day_of_month first_day
FROM data t
left JOIN dim_date m
on
( first_day_of_month between eventdate and nextdate )
or
( month(t.EventDate)=month(first_day_of_month) )
or
( first_day_of_month=dateadd(d,1,eomonth(eventdate)) and nextdate is null)
order by id,EventDate
option (maxrecursion 500)
Результат запроса на этих тестовых данных
| d | EventDate | value | n | nextdate | EventDate0 | first_day |
|---|---|---|---|---|---|---|
| 4 | 2022-12-30 | 100.0 | 0 | 2023-01-04 | 2022-12-30 | 2022-12-01 |
| 4 | 2023-01-01 | 100.0 | 1 | 2023-01-04 | 2022-12-30 | 2023-01-01 |
| 4 | 2023-01-04 | 200.0 | 1 | 2023-01-07 | 2023-01-04 | 2023-01-01 |
| 4 | 2023-01-07 | 300.0 | 1 | 2023-02-08 | 2023-01-07 | 2023-01-01 |
| 4 | 2023-02-01 | 300.0 | 2 | 2023-02-08 | 2023-01-07 | 2023-02-01 |
| 4 | 2023-02-08 | 201.0 | 2 | null | 2023-02-08 | 2023-02-01 |
| 4 | 2023-03-01 | 201.0 | 3 | null | 2023-02-08 | 2023-03-01 |
| 5 | 2023-01-04 | 250.0 | 1 | 2023-03-31 | 2023-01-04 | 2023-01-01 |
| 5 | 2023-02-01 | 250.0 | 2 | 2023-03-31 | 2023-01-04 | 2023-02-01 |
| 5 | 2023-03-01 | 250.0 | 3 | 2023-03-31 | 2023-01-04 | 2023-03-01 |
| 5 | 2023-03-31 | 350.0 | 3 | 2023-04-01 | 2023-03-31 | 2023-03-01 |
| 5 | 2023-04-01 | 350.0 | 4 | 2023-04-01 | 2023-03-31 | 2023-04-01 |
| 5 | 2023-04-01 | 360.0 | 4 | null | 2023-04-01 | 2023-04-01 |
| 5 | 2023-05-01 | 360.0 | 5 | null | 2023-04-01 | 2023-05-01 |
При выборке следующей даты, используем признак отстутвия следующей записи по данному Id - null в поле nextdate. Также имеется 2 записи в результате с датой 2023-04-01 а)на начало месяца б)за этот день.
Структрура и назначение Вашей талблицы dim_date так и осталась неизвестной;)