diff --git a/etc/db/21.sql b/etc/db/21.sql new file mode 100644 index 0000000..c171aa6 --- /dev/null +++ b/etc/db/21.sql @@ -0,0 +1,92 @@ +--explain analyze +-- обсчет примерно 1 день за секунду +-- попробовать оптимизировать base_line +-- попробовать убрать mv +-- pricing_model +-- ВПР время выполнения резко увеличивается при переносе или просто добавлении agreement_is_actual AND в CTE, необъяснимо. Индекс не помогает. Добавление в общее условие where может очень сильно ускорить. Добавление в несколько мест может сильно ускорить +-- ага. тут есть ошибка - возвращается разное количество строк. Что говорит о существенной ошибке в запросе + +with line as (SELECT *, +coalesce((LEAD(dt_from) OVER (PARTITION BY line_key ORDER BY dt_from, agreement_version,line_version)), (select max(dt) from elma.mv_dt)) dt_next +FROM +( + SELECT *, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM elma.mv_line where siv_is_actual AND probability_pc > 0 +) t +WHERE t.dt_from=t.running_min_dt), + +base_line as (SELECT *, +coalesce((LEAD(dt_from) OVER (PARTITION BY line_key ORDER BY dt_from, agreement_version,line_version)), (select max(dt) from elma.mv_dt)) dt_next, +max(agreement_version) OVER (PARTITION BY line_key) max_agr_ver +FROM +( + SELECT *, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM elma.mv_line where siv_is_actual AND deal_status_id IN ('5','6') +) t +WHERE t.dt_from=t.running_min_dt) + +select dayscale.dt +,sum (c.cost/dayscale.monthdays*w.probability_pc/100) +,sum( + case when (w.dt_to > dayscale.dt OR w.dt_to IS NULL) then + c.cost*COALESCE( + case when w.agreement_is_actual then 100 else w.probability_pc end + ,0)/100/dayscale.monthdays + else 0 + end +) as rec1 +,sum( + case when (b.dt_to > dayscale.dt OR b.dt_to IS NULL) then 0 else + cb.cost*(100-COALESCE( + case when w.agreement_is_actual then 100 else w.probability_pc end + ,0))/100/dayscale.monthdays + end +) as rec0 +,sum( + COALESCE(case when (w.dt_to > dayscale.dt OR w.dt_to IS NULL) then + c.cost*( + case when w.agreement_is_actual then 100 else w.probability_pc end + )/100/dayscale.monthdays + else 0 /*по окончании рабочей сделки она дает нулевой вклад*/ + end,0) + + + COALESCE(case when (b.dt_to > dayscale.dt OR b.dt_to IS NULL) then + cb.cost/dayscale.monthdays*(100- COALESCE( + case when w.agreement_is_actual then 100 else w.probability_pc end + ,0))/100 + else 0 /*по окончании базовой сделки она дает нулевой вклад*/ + end,0) + ) +,max(w.dt_from),max(b.dt_from), max(w.probability_pc) +,count(*) +--,w.line_key, w.dt_from, w.dt_to, w.line_version, w.agreement_version, w.deal_status_id, w.contract, w.probability_pc +from +elma.mv_dt dayscale +left outer join line w on (dayscale.dt >=w.dt_from AND dayscale.dt < w.dt_next) +join elma.mv_component c on (w.siv_uid=c.siv_uid) + + +left outer join base_line b on +(b.agreement_is_actual AND w.line_key = b.line_key AND dayscale.dt >= b.dt_from AND dayscale.dt < b.dt_next +AND b.agreement_version = ( + select max(agreement_version) + from base_line i + where i.line_key = w.line_key AND dayscale.dt >= i.dt_from AND dayscale.dt < i.dt_next + AND (w.agreement_version > i.agreement_version OR w.agreement_version IS NULL) +) +) +left outer join elma.mv_component cb on (b.siv_uid=cb.siv_uid) + +where 1=1 +AND dayscale.dt between '2025-03-01' AND '2025-03-05' +--AND w.line_key='0bfd4bfd-641b-444b-9571-b1ab3b00631e' + + +group by dayscale.dt +order by dayscale.dt + +-- select * from elma.mv_line where line_key='0bfd4bfd-641b-444b-9571-b1ab3b00631e' AND probability_pc=100 order by agreement_version, line_version +-- select * from elma.mv_line where dt_from between '2025-03-01' AND '2025-03-03' + diff --git a/etc/db/22.sql b/etc/db/22.sql new file mode 100644 index 0000000..79c25f4 --- /dev/null +++ b/etc/db/22.sql @@ -0,0 +1,67 @@ +--explain analyze +with +component as ( +select siv.__id as siv_uid, siv.discount, siv.cnt as quantity, siv.type as pricing_model_id +,siv.hash as line_key, siv.user_description, siv.is_actual as siv_is_actual +,siv.version, GREATEST(siv.date_nop,d."_plannedDueDate") as dt_from, siv.date_end as dt_to, siv.is_easy as is_simple, siv.cnt as quantity +, a.__id as agreement_uid, a.contract_uid, a.is_actual as agreement_is_actual, a.deal_uid +,d."_plannedDueDate", d.__name as deal +,p.code, p.price, p.cnt as param_quantity, p.discount as param_discount, p.name as sku +,p.price*p.cnt*(100-p.discount)/100 as cost +from elma.deals_services siv +join elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement)) +join elma.deals d on (d.__id = ANY(siv.deal)) +join elma.service_parametrs p on (p.__id = ANY (siv.params)) +join elma.aggrements c on (a.contract_uid = c.__id) +), + + +dayscale as (SELECT dd::date as dt + , DATE_PART('days', DATE_TRUNC('month', dd) + '1 MONTH'::INTERVAL - '1 DAY'::INTERVAL) monthdays + FROM generate_series( + '2025-01-01'::timestamp + ,'2025-12-10'::timestamp + ,'1 day'::interval) dd + ) + +select * from +dayscale +LEFT OUTER JOIN +( +SELECT t.*, +coalesce((LEAD(t.dt_from) OVER (PARTITION BY t.line_key ORDER BY t.dt_from, t.agreement_version,t.line_version)), (select max(dt) from elma.mv_dt)) dt_next, +b.probability_pc, b.discount + +FROM + + +( + SELECT *, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM elma.mv_line where siv_is_actual AND probability_pc > 0 +) t + +LEFT OUTER JOIN + +( select * from -- базовая лесенка + ( + SELECT *, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM elma.mv_line where siv_is_actual AND probability_pc=100 AND agreement_is_actual + ) i where i.dt_from=i.running_min_dt +) b on (b.siv_uid=(select siv_uid from + ( -- базовая лесенка + SELECT siv_uid, dt_from, agreement_version, line_version, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc, line_version desc) running_min_dt + FROM elma.mv_line where siv_is_actual AND probability_pc=100 AND agreement_is_actual + ) i where i.dt_from=i.running_min_dt + AND i.dt_from < t.dt_from + ORDER BY /*dt_from desc,*/ agreement_version desc, line_version desc + LIMIT 1 +)) +where t.dt_from=t.running_min_dt -- это условие формирования лесенки, далко оторвано от ее селекта +AND t.line_pricing_model_id in (2,3) + +--AND t.line_key in ('0a61f9e4-520b-4f0a-aac0-c1d42c037e1b','0bde160d-52d0-4d55-b4e0-05f45cfd739e','08485a0c-a913-4332-bb36-e40dec27d12e','1809bb31-4d37-424b-ba2b-26b9a873af7f') +) o +on (dayscale.dt between o.dt_from AND o.dt_next) \ No newline at end of file diff --git a/etc/db/23.sql b/etc/db/23.sql new file mode 100644 index 0000000..798f34f --- /dev/null +++ b/etc/db/23.sql @@ -0,0 +1,112 @@ +--explain analyze +with + +status(status, status_id, probability_pc) as (VALUES + ('Закрыта неуспешно',7,0),('Закрыта успешно',6,100),('Договор подписан',5,100),('Договор на подписании',15,90),('Договор на согласовании',12,70), + ('Тестирование',8,50),('Отправлено ТКП',10,20),('Внутреннее согласование',37,10),('Проработка решения',4,10),('Сбор потребностей',1,0) +), + +end_of_scale (dt) as (values ('2025-02-02'::timestamp)), -- этот изыск не дает видимого ускорения +dayscale as ( + SELECT dd::date as dt + , DATE_PART('days', DATE_TRUNC('month', dd) + '1 MONTH'::INTERVAL - '1 DAY'::INTERVAL) monthdays + FROM end_of_scale, generate_series( + '2025-01-01'::timestamp + , end_of_scale.dt + ,'1 day'::interval) dd +), +line as ( + select siv.__id as siv_uid, siv.discount, siv.type as line_pricing_model_id + ,siv.hash as line_key, siv.user_description, siv.is_actual as siv_is_actual + ,siv.version::numeric as line_version + , GREATEST(siv.date_nop,d."_plannedDueDate")::date as dt_from + , COALESCE(siv.date_end::date, end_of_scale.dt) as dt_to + ,siv.is_easy as is_simple, siv.cnt as quantity -- maybe should mutliply + , a.__id as agreement_uid, a.contract_uid, a.is_actual as agreement_is_actual, a.deal_uid, a.index as agreement_version + ,d."_plannedDueDate", d.__name as deal, d.__status_status as deal_status_id + ,c.__name as contract + ,s.probability_pc + ,(select sum(p.price*p.cnt*(100-p.discount)/100) from elma.service_parametrs p where(p.__id = ANY (siv.params))) as cost + from elma.deals_services siv + join elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement)) + join elma.deals d on (d.__id = ANY(siv.deal)) + join elma.aggrements c on (a.contract_uid = c.__id) + join status s on (d.__status_status=s.status_id) + cross join end_of_scale +) +-- можно dt_to заменить на верх шкалы + + +select dayscale.dt +,sum (o.cost/dayscale.monthdays*o.probability_pc/100) as sum_unbounded +,sum( + case when (o.dt_to > dayscale.dt /*OR o.dt_to IS NULL*/) then + o.cost*COALESCE( + case when o.agreement_is_actual then 100 else o.probability_pc end + ,0)/100/dayscale.monthdays + else 0 + end +) as sum_working +,sum( + case when (o.dt_to_base > dayscale.dt /*OR o.dt_to_base IS NULL*/) then 0 else + o.cost_base*(100-COALESCE( + case when o.agreement_is_actual then 100 else o.probability_pc end + ,0))/100/dayscale.monthdays + end +) as sum_base +,sum( + COALESCE(case when (o.dt_to > dayscale.dt /*OR o.dt_to IS NULL*/) then + o.cost*( + case when o.agreement_is_actual then 100 else o.probability_pc end + )/100/dayscale.monthdays + else 0 /*по окончании рабочей сделки она дает нулевой вклад*/ + end,0) + + + COALESCE(case when (o.dt_to_base > dayscale.dt /*OR o.dt_to_base IS NULL*/) then + o.cost_base/dayscale.monthdays*(100- COALESCE( + case when o.agreement_is_actual then 100 else o.probability_pc end + ,0))/100 + else 0 /*по окончании базовой сделки она дает нулевой вклад*/ + end,0) + ) as sum_bounded +,max(o.dt_from) as max_dt_from, max(o.dt_from_base) as max_dt_from_base, max(o.probability_pc) as max_probability_pc +,count(*) +from dayscale +LEFT OUTER JOIN ( +SELECT t.*, +coalesce((LEAD(t.dt_from) OVER (PARTITION BY t.line_key ORDER BY t.dt_from, t.agreement_version,t.line_version)), (select max(dt) from elma.mv_dt)) dt_next, +b.discount as discount_base, b.quantity as quantity_base, b.dt_from as dt_from_base, b.dt_to as dt_to_base, b.cost as cost_base + +FROM ( + SELECT *, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM line where siv_is_actual AND probability_pc > 0 +) t + +LEFT OUTER JOIN ( + select * from -- базовая лесенка + ( + SELECT *, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM line where siv_is_actual AND probability_pc=100 AND agreement_is_actual AND deal_status_id in (5,6) + ) i where i.dt_from=i.running_min_dt +) b on (b.siv_uid=( + select siv_uid from + ( -- базовая лесенка + SELECT siv_uid, dt_from, agreement_version, line_version, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc, line_version desc) running_min_dt + FROM line where siv_is_actual AND probability_pc=100 AND agreement_is_actual AND deal_status_id in (5,6) + ) i where i.dt_from=i.running_min_dt + AND i.dt_from < t.dt_from + ORDER BY /*dt_from desc,*/ agreement_version desc, line_version desc + LIMIT 1 +) +) +where t.dt_from=t.running_min_dt -- это условие формирования лесенки, далко оторвано от ее селекта +AND t.line_pricing_model_id in (2,3) + +--AND t.line_key in ('0a61f9e4-520b-4f0a-aac0-c1d42c037e1b','0bde160d-52d0-4d55-b4e0-05f45cfd739e','08485a0c-a913-4332-bb36-e40dec27d12e','1809bb31-4d37-424b-ba2b-26b9a873af7f') +) o +on (o.dt_from <= dayscale.dt AND dayscale.dt < o.dt_next) +group by dayscale.dt +order by dayscale.dt \ No newline at end of file diff --git a/etc/db/24.sql b/etc/db/24.sql new file mode 100644 index 0000000..145b66a --- /dev/null +++ b/etc/db/24.sql @@ -0,0 +1,109 @@ +--explain analyze +with +status(status, status_id, probability_pc) as (VALUES + ('Закрыта неуспешно',7,0),('Закрыта успешно',6,100),('Договор подписан',5,100),('Договор на подписании',15,90),('Договор на согласовании',12,70), + ('Тестирование',8,50),('Отправлено ТКП',10,20),('Внутреннее согласование',37,10),('Проработка решения',4,10),('Сбор потребностей',1,0) +), +begin_of_scale (dt) as (values ('2025-01-01'::timestamp)), -- этот изыск не дает видимого ускорения +end_of_scale (dt) as (values ('2025-12-01'::timestamp)), -- этот изыск не дает видимого ускорения +dayscale as ( + SELECT dd::date as dt + , DATE_PART('days', DATE_TRUNC('month', dd) + '1 MONTH'::INTERVAL - '1 DAY'::INTERVAL) monthdays + FROM begin_of_scale, end_of_scale, generate_series( + begin_of_scale.dt + ,end_of_scale.dt + ,'1 day'::interval) dd +), +line as ( + select siv.__id as siv_uid, siv.discount, siv.type as line_pricing_model_id + ,siv.hash as line_key, siv.user_description, siv.is_actual as siv_is_actual + ,siv.version::numeric as line_version + , GREATEST(siv.date_nop,d."_plannedDueDate")::date as dt_from + , COALESCE(siv.date_end::date, end_of_scale.dt) as dt_to -- не дало видимого ускорения + ,siv.is_easy as is_simple, siv.cnt as quantity -- maybe should mutliply + , a.__id as agreement_uid, a.contract_uid, a.is_actual as agreement_is_actual, a.deal_uid, a.index as agreement_version + ,d."_plannedDueDate", d.__name as deal, d.__status_status as deal_status_id + ,c.__name as contract + ,s.probability_pc + ,(select sum(p.price*p.cnt*(100-p.discount)/100) from elma.service_parametrs p where(p.__id = ANY (siv.params))) as cost + from elma.deals_services siv + join elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement)) + join elma.deals d on (d.__id = ANY(siv.deal)) + join elma.aggrements c on (a.contract_uid = c.__id) + join status s on (d.__status_status=s.status_id) + cross join end_of_scale +) + +select dayscale.dt +,sum (o.cost/dayscale.monthdays*o.probability_pc/100) as sum_unbounded +,sum( + case when (o.dt_to > dayscale.dt /*OR o.dt_to IS NULL*/) then + o.cost*COALESCE( + case when o.agreement_is_actual then 100 else o.probability_pc end + ,0)/100/dayscale.monthdays + else 0 + end +) as sum_working +,sum( + case when (o.dt_to_base > dayscale.dt /*OR o.dt_to_base IS NULL*/) then 0 else + o.cost_base*(100-COALESCE( + case when o.agreement_is_actual then 100 else o.probability_pc end + ,0))/100/dayscale.monthdays + end +) as sum_base +,sum( + COALESCE(case when (o.dt_to > dayscale.dt /*OR o.dt_to IS NULL*/) then + o.cost*( + case when o.agreement_is_actual then 100 else o.probability_pc end + )/100/dayscale.monthdays + else 0 /*по окончании рабочей сделки она дает нулевой вклад*/ + end,0) + + + COALESCE(case when (o.dt_to_base > dayscale.dt /*OR o.dt_to_base IS NULL*/) then + o.cost_base/dayscale.monthdays*(100- COALESCE( + case when o.agreement_is_actual then 100 else o.probability_pc end + ,0))/100 + else 0 /*по окончании базовой сделки она дает нулевой вклад*/ + end,0) + ) as sum_bounded +,max(o.dt_from) as max_dt_from, max(o.dt_from_base) as max_dt_from_base, max(o.probability_pc) as max_probability_pc +,count(*) +from dayscale +LEFT OUTER JOIN ( +SELECT t.*, +coalesce((LEAD(t.dt_from) OVER (PARTITION BY t.line_key ORDER BY t.dt_from, t.agreement_version,t.line_version)), (select max(dt) from elma.mv_dt)) dt_next, +b.discount as discount_base, b.quantity as quantity_base, b.dt_from as dt_from_base, b.dt_to as dt_to_base, b.cost as cost_base + +FROM ( + SELECT *, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM line where siv_is_actual AND probability_pc > 0 +) t + +LEFT OUTER JOIN ( + select * from -- базовая лесенка + ( + SELECT *, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM line where siv_is_actual AND probability_pc=100 AND agreement_is_actual AND deal_status_id in (5,6) + ) i where i.dt_from=i.running_min_dt +) b on (t.line_key=b.line_key AND b.siv_uid=( + select siv_uid from + ( -- базовая лесенка + SELECT siv_uid, dt_from, agreement_version, line_version, + MIN(dt_from) OVER (PARTITION BY line_key ORDER BY agreement_version desc, line_version desc) running_min_dt + FROM line where siv_is_actual AND probability_pc=100 AND agreement_is_actual AND deal_status_id in (5,6) + ) i where i.dt_from=i.running_min_dt + AND i.dt_from < t.dt_from + ORDER BY /*dt_from desc,*/ agreement_version desc, line_version desc + LIMIT 1 +) +) +where t.dt_from=t.running_min_dt -- это условие формирования лесенки, далко оторвано от ее селекта +AND t.line_pricing_model_id in (2,3) + +--AND t.line_key in ('0a61f9e4-520b-4f0a-aac0-c1d42c037e1b','0bde160d-52d0-4d55-b4e0-05f45cfd739e','08485a0c-a913-4332-bb36-e40dec27d12e','1809bb31-4d37-424b-ba2b-26b9a873af7f') +) o +on (o.dt_from <= dayscale.dt AND dayscale.dt < o.dt_next) +group by dayscale.dt +order by dayscale.dt \ No newline at end of file diff --git a/etc/db/install-24.sql b/etc/db/install-24.sql new file mode 100644 index 0000000..52272a2 --- /dev/null +++ b/etc/db/install-24.sql @@ -0,0 +1,71 @@ +--explain analyze +with +status(status, status_id, probability_pc) as (VALUES + ('Закрыта неуспешно',7,0),('Закрыта успешно',6,100),('Договор подписан',5,100),('Договор на подписании',15,90),('Договор на согласовании',12,70), + ('Тестирование',8,50),('Отправлено ТКП',10,20),('Внутреннее согласование',37,10),('Проработка решения',4,10),('Сбор потребностей',1,0) +), +begin_of_scale (dt) as (values ('2025-01-01'::timestamp)), -- этот изыск не дает видимого ускорения +end_of_scale (dt) as (values ('2025-12-02'::timestamp)), -- этот изыск не дает видимого ускорения +dayscale as ( + SELECT dd::date as dt + , DATE_PART('days', DATE_TRUNC('month', dd) + '1 MONTH'::INTERVAL - '1 DAY'::INTERVAL) monthdays + FROM begin_of_scale, end_of_scale, generate_series( + begin_of_scale.dt + ,end_of_scale.dt + ,'1 day'::interval) dd +), +line as ( + select siv.__id as siv_uid, siv.discount, siv.type as line_pricing_model_id + ,siv.hash as line_key, siv.user_description, siv.is_actual as siv_is_actual + ,siv.version::numeric as line_version + , GREATEST(siv.date_nop,d."_plannedDueDate")::date as dt_from + , COALESCE(siv.date_end::date, end_of_scale.dt) as dt_to + ,siv.is_easy as is_simple, siv.cnt as quantity -- maybe should mutliply + , a.__id as agreement_uid, a.contract_uid, a.is_actual as agreement_is_actual, a.deal_uid, a.index as agreement_version + ,d."_plannedDueDate", d.__name as deal, d.__status_status as deal_status_id + ,c.__name as contract + ,s.probability_pc + ,(select sum(p.price*p.cnt*(100-p.discount)/100) from elma.service_parametrs p where(p.__id = ANY (siv.params))) as cost + from elma.deals_services siv + join elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement)) + join elma.deals d on (d.__id = ANY(siv.deal)) + join elma.aggrements c on (a.contract_uid = c.__id) + join status s on (d.__status_status=s.status_id) + cross join end_of_scale +) + +select dayscale.dt +,sum (o.cost/dayscale.monthdays*o.probability_pc/100) as sum_unbounded +,sum(o.cost*o.probability_pc/100) as sum_working +,sum(o.cost_base*(100-COALESCE(o.probability_pc,0))) as sum_base +,( + COALESCE(sum(o.cost*o.probability_pc/100),0) + + + COALESCE(sum(o.cost_base*(100-COALESCE(o.probability_pc,0))),0) + ) as sum_bounded +,max(o.dt_from) as max_dt_from, max(o.dt_from_base) as max_dt_from_base, max(o.probability_pc) as max_probability_pc +,count(*) + +from dayscale +LEFT OUTER JOIN ( +SELECT t.*, +b.discount as discount_base, b.quantity as quantity_base, b.dt_from as dt_from_base, b.dt_to as dt_to_base, b.cost as cost_base + +FROM line t + +LEFT OUTER JOIN line b on (t.line_key=b.line_key AND b.siv_uid=( + select siv_uid + FROM line where siv_is_actual AND probability_pc=100 AND agreement_is_actual AND deal_status_id in (5,6) + AND ((t.agreement_version > b.agreement_version) OR (t.agreement_version = b.agreement_version AND t.line_version > b.line_version)) + ORDER BY agreement_version desc, line_version desc + LIMIT 1 + ) +) +where 1=1 +AND t.line_pricing_model_id in (1) + +--AND t.line_key in ('0a61f9e4-520b-4f0a-aac0-c1d42c037e1b','0bde160d-52d0-4d55-b4e0-05f45cfd739e','08485a0c-a913-4332-bb36-e40dec27d12e','1809bb31-4d37-424b-ba2b-26b9a873af7f') +) o +on (o.dt_from = dayscale.dt) +group by dayscale.dt +order by dayscale.dt \ No newline at end of file diff --git a/etc/db/mv.sql b/etc/db/mv.sql index 244f6ca..710794d 100644 --- a/etc/db/mv.sql +++ b/etc/db/mv.sql @@ -21,7 +21,8 @@ left outer join status s on (d.__status_status=s.status_id) where siv.is_actual ); CREATE UNIQUE INDEX UX_mv_line_id on elma.mv_line (siv_uid); -CREATE INDEX IX_mv_line_m on elma.mv_line (line_key,dt_from,line_version,agreement_version,siv_uid); +CREATE INDEX IX_mv_line_m on elma.mv_line (line_key,dt_from,line_version,agreement_version,siv_uid,agreement_is_actual); +--CREATE INDEX IX_mv_line_b on elma.mv_line (line_key,dt_from,line_version,agreement_version,agreement_is_actual,siv_uid,siv_is_actual, deal_status_id); drop materialized view if exists elma.mv_component cascade; create materialized view elma.mv_component as ( diff --git a/etc/db/non-trivial-dates.sql b/etc/db/non-trivial-dates.sql index a377a49..eb185fb 100644 --- a/etc/db/non-trivial-dates.sql +++ b/etc/db/non-trivial-dates.sql @@ -2,4 +2,11 @@ left outer join elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement)) left outer join elma.deals d on (d.__id = ANY(siv.deal)) where d.__status_status in(5,6) group by hash having count(distinct GREATEST(siv.date_nop,d."_plannedDueDate")) > 1 + + select hash, siv.type, count(*), count(distinct siv.date_nop), count(distinct d."_plannedDueDate"), count(distinct GREATEST(siv.date_nop,d."_plannedDueDate")) + from elma.deals_services siv + left outer join elma.additional_agreements a on (a.__id = ANY(siv.additional_agreement)) + left outer join elma.deals d on (d.__id = ANY(siv.deal)) + where d.__status_status in(5,6) AND siv.type=2 + group by hash, siv.type having count(distinct GREATEST(siv.date_nop,d."_plannedDueDate")) > 1 -- \ No newline at end of file diff --git a/etc/db/val-01.sql b/etc/db/val-01.sql new file mode 100644 index 0000000..77fd202 --- /dev/null +++ b/etc/db/val-01.sql @@ -0,0 +1,15 @@ +with siv (dt_from, agreement_version, line_version, agreement_is_actual, siv_is_actual, cost, prob) +as (VALUES +('2025-01-01'::date, 1, 1, true, true, 100, 100), +('2025-02-01', 1, 10, false, true, 200, 10), +('2025-02-01', 1, 12, true, true, 200, 100), +('2025-03-01', 2, 20, true, true, 100, 100), +('2025-03-01', 2, 21, true, true, 150, 100), +('2025-02-15', 3, 30, true, true, 300, 100), +('2025-04-01', 4, 40, false, true, 100, 100) +) +SELECT +(LAST_VALUE (dt_from) OVER (ORDER BY dt_from, agreement_version,line_version RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)), +--coalesce((LEAD(dt_from) OVER (ORDER BY dt_from, agreement_version,line_version)), (select max(dt) from elma.mv_dt)) dt_next, +* +from siv \ No newline at end of file diff --git a/etc/db/val-02.sql b/etc/db/val-02.sql new file mode 100644 index 0000000..4962a27 --- /dev/null +++ b/etc/db/val-02.sql @@ -0,0 +1,32 @@ +with siv (dt_from, agreement_version, line_version, agreement_is_actual, siv_is_actual, cost, prob) +as (VALUES +('2025-01-01'::date, 1, 1, true, true, 100, 100), +('2025-02-01', 1, 10, false, true, 200, 10), +('2025-02-01', 1, 12, true, true, 200, 100), +('2025-03-01', 2, 20, true, true, 100, 100), +('2025-03-01', 2, 21, true, true, 150, 100), +('2025-02-15', 3, 30, true, true, 300, 100), +('2025-04-01', 4, 40, false, true, 100, 100), +('2025-03-15', 2, 25, false, false, 1000, 50) +) +--SELECT +--(LAST_VALUE (dt_from) OVER (ORDER BY dt_from, agreement_version,line_version RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)), +--coalesce((LEAD(dt_from) OVER (ORDER BY dt_from, agreement_version,line_version)), (select max(dt) from elma.mv_dt)) dt_next, +--* from siv +-- выбрать рабочую лесенку и базовую лесенку, посмотреть на них +SELECT b.agreement_version, b.line_version, t.*, +coalesce((LEAD(t.dt_from) OVER (/*PARTITION BY line_key*/ ORDER BY t.dt_from, t.agreement_version,t.line_version)), (select max(dt) from elma.mv_dt)) dt_next +FROM +( + SELECT *, + MIN(dt_from) OVER (/*PARTITION BY line_key*/ ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM siv where siv_is_actual AND prob > 0 +) t +left outer join +( + SELECT *, + MIN(dt_from) OVER (/*PARTITION BY line_key*/ ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM siv where siv_is_actual AND prob=100 AND agreement_is_actual +) b on (t.dt_from=b.dt_from AND b.dt_from=b.running_min_dt) +WHERE t.dt_from=t.running_min_dt + diff --git a/etc/db/val-03.sql b/etc/db/val-03.sql new file mode 100644 index 0000000..966ec0d --- /dev/null +++ b/etc/db/val-03.sql @@ -0,0 +1,42 @@ +with siv (id, dt_from, agreement_version, line_version, agreement_is_actual, siv_is_actual, cost, prob) +as (VALUES +(1,'2025-01-01'::date, 1, 1, true, true, 100, 100), +(2,'2025-02-01', 1, 10, false, true, 200, 10), +(3,'2025-02-01', 1, 12, true, true, 200, 100), +(4,'2025-03-01', 2, 20, true, true, 100, 100), +(5,'2025-03-01', 2, 21, true, true, 150, 100), +(6,'2025-02-15', 3, 30, true, true, 300, 100), +(7,'2025-04-01', 4, 40, false, true, 100, 100), +(8,'2025-03-15', 2, 25, false, false, 1000, 50) +) +--SELECT +--(LAST_VALUE (dt_from) OVER (ORDER BY dt_from, agreement_version,line_version RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)), +--coalesce((LEAD(dt_from) OVER (ORDER BY dt_from, agreement_version,line_version)), (select max(dt) from elma.mv_dt)) dt_next, +--* from siv +-- выбрать рабочую лесенку и базовую лесенку, посмотреть на них +SELECT t.*, +coalesce((LEAD(t.dt_from) OVER (/*PARTITION BY line_key*/ ORDER BY t.dt_from, t.agreement_version,t.line_version)), (select max(dt) from elma.mv_dt)) dt_next, +(select id from + ( + SELECT *, + MIN(dt_from) OVER (/*PARTITION BY line_key*/ ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM siv where siv_is_actual AND prob=100 AND agreement_is_actual + ) b where b.dt_from=b.running_min_dt + AND b.dt_from <= t.dt_from + ORDER BY dt_from desc, agreement_version desc,line_version desc + LIMIT 1 +) + +FROM +( + SELECT *, + MIN(dt_from) OVER (/*PARTITION BY line_key*/ ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM siv where siv_is_actual AND prob > 0 +) t where t.dt_from=t.running_min_dt + + +-- пытаюсь построить более эффективный расчет, нежели по каждой дате. По каждой дате сформулировать условия достаточно просто, но вычислений выходит очень много +-- может попробовать повторить исходный расчет, но с оконными функциями (вместо подзапроса максимальной версии) +-- вспомним, что проблема усложнилась, когда у нас не оказалось единой версии, а версия из 2 полей +-- может быть, полезными окажутся какие-то ограничения, скажем, уникальность версии совместно с siv_is_actual (смутные воспоминания) + diff --git a/etc/db/val-04.sql b/etc/db/val-04.sql new file mode 100644 index 0000000..e2377f0 --- /dev/null +++ b/etc/db/val-04.sql @@ -0,0 +1,53 @@ +with siv (id, dt_from, agreement_version, line_version, agreement_is_actual, siv_is_actual, cost, prob) +as (VALUES +(10,'2025-01-01'::date, 1, 1, true, true, 100, 100), +(20,'2025-02-01', 1, 10, false, true, 200, 10), +(30,'2025-02-01', 1, 12, true, true, 200, 100), +(35,'2025-02-01', 1, 13, true, true, 250, 100), +(40,'2025-03-01', 2, 20, true, true, 100, 100), +(50,'2025-03-01', 2, 21, true, true, 150, 100), +(60,'2025-02-15', 3, 30, true, true, 300, 100), +(70,'2025-04-01', 4, 40, false, true, 100, 100), +(80,'2025-03-15', 2, 25, false, false, 1000, 50) +) +-- может ли базовая версия быть старше рабочей ВПР +--SELECT +--(LAST_VALUE (dt_from) OVER (ORDER BY dt_from, agreement_version,line_version RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)), +--coalesce((LEAD(dt_from) OVER (ORDER BY dt_from, agreement_version,line_version)), (select max(dt) from elma.mv_dt)) dt_next, +--* from siv +-- выбрать рабочую лесенку и базовую лесенку, посмотреть на них +SELECT t.*, +coalesce((LEAD(t.dt_from) OVER (/*PARTITION BY line_key*/ ORDER BY t.dt_from, t.agreement_version,t.line_version)), (select max(dt) from elma.mv_dt)) dt_next, +b.* + +FROM +( + SELECT *, + MIN(dt_from) OVER (/*PARTITION BY line_key*/ ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM siv where siv_is_actual AND prob > 0 +) t +LEFT OUTER JOIN +( select * from -- базовая лесенка + ( + SELECT *, + MIN(dt_from) OVER (/*PARTITION BY line_key*/ ORDER BY agreement_version desc,line_version desc) running_min_dt + FROM siv where siv_is_actual AND prob=100 AND agreement_is_actual + ) i where i.dt_from=i.running_min_dt + +) b on (b.id=(select id from + ( -- базовая лесенка + SELECT id, dt_from, agreement_version, line_version, + MIN(siv.dt_from) OVER (/*PARTITION BY line_key*/ ORDER BY siv.agreement_version desc,siv.line_version desc) running_min_dt + FROM siv where siv_is_actual AND prob=100 AND agreement_is_actual + ) i where i.dt_from=i.running_min_dt + AND i.dt_from < t.dt_from + ORDER BY /*dt_from desc,*/ agreement_version desc, line_version desc + LIMIT 1 +)) where t.dt_from=t.running_min_dt -- это условие формирования лесенки, очень оторвано от ее селекта + + +-- пытаюсь построить более эффективный расчет, нежели по каждой дате. По каждой дате сформулировать условия достаточно просто, но вычислений выходит очень много +-- может попробовать повторить исходный расчет, но с оконными функциями (вместо подзапроса максимальной версии) +-- вспомним, что проблема усложнилась, когда у нас не оказалось единой версии, а версия из 2 полей +-- может быть, полезными окажутся какие-то ограничения, скажем, уникальность версии совместно с siv_is_actual (смутные воспоминания) + diff --git a/income_daily_rpt.cfm b/income_daily_rpt.cfm index 4c089f1..cac70cc 100644 --- a/income_daily_rpt.cfm +++ b/income_daily_rpt.cfm @@ -157,7 +157,7 @@ from ( join agreement ia on (isp.contract_id=ia.contract_id AND iiv.agreement_version=ia.agreement_version) where iiv.specification_item_uid=siv.specification_item_uid AND (dayscale.dt >= iiv.dt_from /*AND (iiv.dt_to > dayscale.dt OR iiv.dt_to IS NULL)*/))) - /*AND ia.is_actual*/ /*свежее соглашение не обязано быть действующим*/ + /*AND ia.is_actual*/ /*рабочее соглашение не обязано быть действующим*/ join specification_item si on (siv.specification_item_uid=si.specification_item_uid AND si.pricing_model_id in (2,3)) join specification s on (si.specification_id=s.specification_id) join agreement a on (s.contract_id=a.contract_id AND a.agreement_version=siv.agreement_version) @@ -175,7 +175,7 @@ from ( join agreement ia on (isp.contract_id=ia.contract_id AND iiv.agreement_version=ia.agreement_version) where iiv.specification_item_uid=si.specification_item_uid AND ia.agreement_version < siv.agreement_version - AND ia.is_actual /*именно действующее соглашение, принимаемое за факт*/ + AND ia.is_actual /*именно действующее (базовое) соглашение, принимаемое за факт*/ /*а почему тут дату не проверяем ВПР*/ ) )