2016-05-19 5 views
0

У меня есть таблица с историческими cash_balances за день, валюту и страну.SQL: получить значение со второго последнего рабочего дня предыдущего месяца

Мне нужно заполнить столбец под названием «cash_balance_last_month» значениями из столбца «cash_balance» во вторую последнюю деловую дату предыдущего месяца, которая определяется как вторая последняя дата в предыдущем месяце, для которой существует данные в таблице.

Так таблица выглядит следующим образом:

report_date/currency/country/cash_balance/cash_balance_last_month 
2016-03-05/ USD / US / 110 /  NULL 
2016-03-05/ EUR / DE / 130 /  NULL 
2016-03-05/ EUR / FR / 240 /  NULL 
2016-02-05/ USD / US / 105 /  NULL 
2016-02-05/ EUR / DE / 125 /  NULL 
2016-02-05/ EUR / FR / 245 /  NULL 
2016-29-04/ USD / US / 100 /  NULL 
2016-29-04/ EUR / DE / 120 /  NULL 
2016-29-04/ EUR / FR / 250 /  NULL 
2016-28-04/ USD / US /  95 /  NULL 
2016-28-04/ EUR / DE / 115 /  NULL 
2016-28-04/ EUR / FR / 255 /  NULL 
... 
2016-30-03/ USD / US /  90 /  NULL 
2016-30-03/ EUR / DE / 117 /  NULL 
2016-30-03/ EUR / FR / 257 /  NULL 

Обратите внимание, что 2016-30-03 является вторым последним рабочим днем ​​марта.

таблица должна выглядеть следующим образом:

report_date/currency/country/cash_balance/cash_balance_last_month 
2016-03-05/ USD / US / 110 /  95 
2016-03-05/ EUR / DE / 130 /  115 
2016-03-05/ EUR / FR / 240 /  255 
2016-02-05/ USD / US / 105 /  95 
2016-02-05/ EUR / DE / 125 /  115 
2016-02-05/ EUR / FR / 245 /  255 
2016-29-04/ USD / US / 100 /  90 
2016-29-04/ EUR / DE / 120 /  117 
2016-29-04/ EUR / FR / 250 /  257 
2016-28-04/ USD / US /  95 /  90 
2016-28-04/ EUR / DE / 115 /  117 
2016-28-04/ EUR / FR / 255 /  257 
... 
2016-30-03/ USD / US /  90 /  NULL 
2016-30-03/ EUR / DE / 117 /  NULL 
2016-30-03/ EUR / FR / 257 /  NULL 

Первые записи, в этом примере 2016-30-03, очевидно, не имеют предыдущий месяц сослаться.

Как вычислить этот столбец «cash_balance_last_month»? Я не смог понять это сам или найти какие-либо связанные вопросы, которые могли бы помочь мне придумать решение.

Справка будет очень признательна. Спасибо!

+0

у вас есть таблица календаря? Если вы этого не сделаете, вы должны – Squirrel

+0

Нет, я этого не делаю. Любые хорошие решения без одного? – SSA

+1

Кажется, это не зависит от даты календаря, а скорее от наличия данных в таблице. Вы можете просто рассчитать row_number по данным в таблице, поделить его по году/месяцу (и стране?) По дате desc и получить значение из строки, где row_number = 2 за данный месяц-1. – dean

ответ

1
declare @table table 
(report_date datetime , currency varchar(3), country varchar(2), cash_balance int, cash_balance_last_month int) 
insert into @table 
values 
(cast('2016-05-03' as datetime), 'USD' , 'US' ,  110  ,  NULL), 
(cast('2016-05-03' as datetime), 'EUR' , 'DE' ,  130  ,  NULL), 
(cast('2016-05-03' as datetime), 'EUR' , 'FR' ,  240  ,  NULL), 
(cast('2016-05-02' as datetime), 'USD' , 'US' ,  105  ,  NULL), 
(cast('2016-05-02' as datetime), 'EUR' , 'DE' ,  125  ,  NULL), 
(cast('2016-05-02' as datetime), 'EUR' , 'FR' ,  245  ,  NULL), 
(cast('2016-04-29' as datetime), 'USD' , 'US' ,  100  ,  NULL), 
(cast('2016-04-29' as datetime), 'EUR' , 'DE' ,  120  ,  NULL), 
(cast('2016-04-29' as datetime), 'EUR' , 'FR' ,  250  ,  NULL), 
(cast('2016-04-28' as datetime), 'USD' , 'US' ,  95  ,  NULL), 
(cast('2016-04-28' as datetime), 'EUR' , 'DE' ,  115  ,  NULL), 
(cast('2016-04-28' as datetime), 'EUR' , 'FR' ,  255  ,  NULL), 
(cast('2016-03-31' as datetime), 'USD' , 'US' ,  10  ,  NULL), 
(cast('2016-03-31' as datetime), 'EUR' , 'DE' ,  10  ,  NULL), 
(cast('2016-03-31' as datetime), 'EUR' , 'FR' ,  10  ,  NULL), 
(cast('2016-03-30' as datetime), 'USD' , 'US' ,  90  ,  NULL), 
(cast('2016-03-30' as datetime), 'EUR' , 'DE' ,  117  ,  NULL), 
(cast('2016-03-30' as datetime), 'EUR' , 'FR' ,  257  ,  NULL) 

select t1.report_date,t1.currency,t1.country,t1.cash_balance, s.cash_balance as cash_balance_last_month 
from @table t1 
left join 
(
select t1.*, 
     year(t1.report_date) * 12 + month(t1.report_date) monthnum, 
     row_number() over(partition by year(t1.report_date) * 100 + month(t1.report_date), t1.country order by t1.report_date desc) rn 
from @table t1 
) s 
on s.monthnum = (year(t1.report_date) * 12 + month(t1.report_date)) - 1 
    and t1.country = s.country and t1.currency = s.currency 
    and s.rn = 2 
+0

Даты, локализованные в Великобритании. Трюк должен рассчитать месяц, а также номер строки. –

+0

Спасибо! Это работало точно так, как требуется – SSA

Смежные вопросы