-- Пересчёт ekb_districts.median_price_per_m2 + mean_price_per_m2 из rosreestr_deals. -- -- Зачем: для половины районов ЕКБ были NULL (импорт Антона из SQLite не покрыл), -- из-за чего recommend_mix давал district_factor=1.0 без учёта района и -- cadastre_vs_market_pct = NULL (нет district_median для сравнения с кадастром). -- Старые значения для Октябрьского/Орджоникидзевского (191K/205K) выглядят как -- yandex/domrf-листинг, не реальные сделки — перезаписываем для консистентности. -- -- Исключаем 'не определён' (служебная категория, не настоящий район). -- -- Идемпотентно — можно перезапускать. Окно 24 мес даёт устойчивые медианы. -- Если в районе <50 сделок за 24 мес — оставляем NULL (warning в recommend_mix). CREATE OR REPLACE FUNCTION refresh_ekb_districts_median(window_months int DEFAULT 24, min_deals int DEFAULT 50) RETURNS TABLE(district_name text, deals_used bigint, median_pm numeric, mean_pm numeric) LANGUAGE plpgsql AS $$ BEGIN RETURN QUERY WITH per_district AS ( SELECT d.district_name, COUNT(*)::bigint AS deals, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY rd.price_per_sqm)::numeric AS p_median, AVG(rd.price_per_sqm)::numeric AS p_mean FROM rosreestr_deals rd JOIN cad_quarters_geom cq ON cq.cad_number = rd.quarter_cad_number JOIN ekb_districts_geom d ON ST_Intersects(d.geom, cq.geom) WHERE rd.region_code = 66 AND rd.doc_type = 'ДДУ' AND rd.realestate_type_code = '002001003000' AND rd.area BETWEEN 15 AND 200 AND rd.price_per_sqm BETWEEN 30000 AND 1000000 AND rd.period_start_date >= NOW() - (window_months || ' months')::interval GROUP BY d.district_name ), upd AS ( UPDATE ekb_districts e SET median_price_per_m2 = ROUND(pd.p_median, 0), mean_price_per_m2 = ROUND(pd.p_mean, 0) FROM per_district pd WHERE e.district_name = pd.district_name AND e.district_name <> 'не определён' AND pd.deals >= min_deals RETURNING e.district_name, pd.deals, pd.p_median, pd.p_mean ) SELECT u.district_name::text, u.deals, ROUND(u.p_median, 0), ROUND(u.p_mean, 0) FROM upd u ORDER BY u.district_name; END; $$; COMMENT ON FUNCTION refresh_ekb_districts_median(int, int) IS 'Refresh ekb_districts.median_price_per_m2 + mean_price_per_m2 из ДДУ-сделок rosreestr_deals ' 'через spatial-join cad_quarters_geom + ekb_districts_geom. Окно по умолчанию 24 мес, ' 'минимум 50 сделок на район. Запускается Celery beat раз в месяц.';