Есть у меня довольно зубодробительный запрос, который упростить пока не получается.
Одно из select-полей выглядит примерно так:
, case FT.FEE_PERIOD_UNIT
when 'D' then trunc(nvl(ST.DATE_BEG, S.START_DATE))
when 'W' then trunc(nvl(ST.DATE_BEG, S.START_DATE)) - decode(FT.FEE_PERIOD_ADJUST, 0, 0, FT.FEE_PERIOD_VALUE - 1 + (trunc(trunc(nvl(ST.DATE_BEG, S.START_DATE)), 'DD') - trunc(trunc(nvl(ST.DATE_BEG, S.START_DATE)), 'IW')))
when 'M' then to_date(to_char(trunc(nvl(ST.DATE_BEG, S.START_DATE)),'YYYY')||to_char(trunc(nvl(ST.DATE_BEG, S.START_DATE)),'MM')||to_char(decode(FT.FEE_PERIOD_ADJUST, 0, extract(day from trunc(nvl(ST.DATE_BEG, S.START_DATE))), FT.FEE_PERIOD_ADJUST), 'FM00'), 'YYYYMMDD')
when 'Y' then to_date(to_char(trunc(nvl(ST.DATE_BEG, S.START_DATE)),'YYYY')||to_char(decode(FT.FEE_PERIOD_ADJUST, 0, extract(month from trunc(nvl(ST.DATE_BEG, S.START_DATE))), FT.FEE_PERIOD_ADJUST), 'FM00')||to_char(decode(FT.FEE_PERIOD_ADJUST, 0, extract(day from trunc(nvl(ST.DATE_BEG, S.START_DATE))), 1), 'FM00'), 'YYYYMMDD')
else null
end as ST_PERIOD_START
Значение ST_PERIOD_START в свою очередь используется в не менее сложных выражениях, а вычисленные выражения используются в других выражениях попроще.
Пробный работающий запрос я для этого трижды оборачивал в подзапросы:
select S2.*
, FEE_PERIOD_NEXT - FEE_PERIOD_CURRENT as FEE_PERIOD_DAYS
from
(
select S1.*
, case FEE_PERIOD_UNIT
when 'D' then trunc((trunc(sysdate) - FEE_PERIOD_START + 1)/FEE_PERIOD_VALUE)
when 'W' then trunc((trunc(sysdate) - FEE_PERIOD_START + 1)/7/FEE_PERIOD_VALUE)
when 'M' then trunc(months_between(trunc(sysdate), FEE_PERIOD_START)/FEE_PERIOD_VALUE)
when 'Y' then trunc(months_between(trunc(sysdate), FEE_PERIOD_START)/12/FEE_PERIOD_VALUE)
else null
end as FEE_PERIOD_COUNT
, case FEE_PERIOD_UNIT
when 'D' then FEE_PERIOD_START + FEE_PERIOD_VALUE*trunc((trunc(sysdate) - FEE_PERIOD_START + 1)/FEE_PERIOD_VALUE)
when 'W' then FEE_PERIOD_START + 7*FEE_PERIOD_VALUE*trunc((trunc(sysdate) - FEE_PERIOD_START + 1)/7/FEE_PERIOD_VALUE)
when 'M' then add_months(FEE_PERIOD_START, FEE_PERIOD_VALUE*trunc(months_between(trunc(sysdate), FEE_PERIOD_START)/FEE_PERIOD_VALUE))
when 'Y' then add_months(FEE_PERIOD_START, 12*FEE_PERIOD_VALUE*trunc(months_between(trunc(sysdate), FEE_PERIOD_START)/12/FEE_PERIOD_VALUE))
else null
end as FEE_PERIOD_CURRENT
, case FEE_PERIOD_UNIT
when 'D' then FEE_PERIOD_START + FEE_PERIOD_VALUE*(1+trunc((trunc(sysdate) - FEE_PERIOD_START + 1)/FEE_PERIOD_VALUE))
when 'W' then FEE_PERIOD_START + 7*FEE_PERIOD_VALUE*(1+trunc((trunc(sysdate) - FEE_PERIOD_START + 1)/7/FEE_PERIOD_VALUE))
when 'M' then add_months(FEE_PERIOD_START, FEE_PERIOD_VALUE*(1+trunc(months_between(trunc(sysdate), FEE_PERIOD_START)/FEE_PERIOD_VALUE)))
when 'Y' then add_months(FEE_PERIOD_START, 12*FEE_PERIOD_VALUE*(1+trunc(months_between(trunc(sysdate), FEE_PERIOD_START)/12/FEE_PERIOD_VALUE)))
else null
end as FEE_PERIOD_NEXT
from
(
select S0.*
, case FEE_PERIOD_UNIT
when 'D' then SERVICE_START
when 'W' then SERVICE_START - decode(FEE_PERIOD_ADJUST, 0, 0, FEE_PERIOD_VALUE - 1 + (trunc(SERVICE_START, 'DD') - trunc(SERVICE_START, 'IW')))
when 'M' then to_date(to_char(SERVICE_START,'YYYY')||to_char(SERVICE_START,'MM')||to_char(decode(FEE_PERIOD_ADJUST, 0, extract(day from SERVICE_START), FEE_PERIOD_ADJUST), 'FM00'), 'YYYYMMDD')
when 'Y' then to_date(to_char(SERVICE_START,'YYYY')||to_char(decode(FEE_PERIOD_ADJUST, 0, extract(month from SERVICE_START), FEE_PERIOD_ADJUST), 'FM00')||to_char(decode(FEE_PERIOD_ADJUST, 0, extract(day from SERVICE_START), 1), 'FM00'), 'YYYYMMDD')
else null
end as FEE_PERIOD_START
from
(
select S.ACCOUNT_ID
...
) FEE on (FEE.TARIFF_ID = T.TARIFF_ID and FEE.TYPE_ID = T.TYPE_ID)
where S.STATUS != -20
) S0
) S1
) S2
Можно конечно все эти выражения развернуть, но тогда для некоторых полей будут выражения на полэкрана.
Для оптимизатора СУБД это скорее всего пустяки, но я сам в такой портянке не разберусь.
Не посоветуете, как можно сократить подобные выражения, может быть есть какой-нибудь «синтаксический сахар» для упрощения подобных конструкций?
Или обернуть в подзапрос будет оптимально?
________________________
Мы смотрим с оптимизмом...
...в оптический прицел.