fix(tradein): guard ГАР-undercount знаменателя в v_building_sale_share (145) (#2064)
All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m29s
Deploy Trade-In / build-backend (push) Successful in 27s
Deploy Trade-In / deploy (push) Successful in 49s
All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m29s
Deploy Trade-In / build-backend (push) Successful in 27s
Deploy Trade-In / deploy (push) Successful in 49s
This commit is contained in:
parent
579536b4ad
commit
57ae2dfe00
1 changed files with 75 additions and 0 deletions
|
|
@ -0,0 +1,75 @@
|
|||
-- 145_building_sale_share_plausible_denom.sql
|
||||
--
|
||||
-- CONTEXT: гейт правдоподобности знаменателя в v_building_sale_share.
|
||||
-- ГАР/ФИАС часто недо-регистрирует помещения (на проде лишь 68 406 из 919 341
|
||||
-- домов региона 66 имеют хоть одно помещение). Малый/неполный flat_count раздувал
|
||||
-- sale_share_pct: топ листа был забит «5 из 5 = 100%», а 91 дом показывал >100%
|
||||
-- (active_secondary > flat_count — физически невозможно, явный undercount).
|
||||
--
|
||||
-- Гейт: sale_share_pct вычисляется ТОЛЬКО когда
|
||||
-- flat_count_effective >= GREATEST(COALESCE(total_floors,0), 8) -- >=1 кв/этаж и не мизер
|
||||
-- AND active_secondary <= flat_count_effective -- не >100%
|
||||
-- иначе NULL («н/д» — честно, без выдуманного процента).
|
||||
--
|
||||
-- Проверено на проде (rollback-tx): 2769 → 2596 достоверных домов (−91 >100%,
|
||||
-- −82 undercount), over100=0; топ — реальные сигналы концентрации продаж
|
||||
-- (Крауля 89А 10/11=90.9%, Ткачей 17 15/19=78.9%, Походная 63 12/32=37.5%).
|
||||
--
|
||||
-- DEPENDENCIES: 143 (view + houses.gar_flat_count), 144 (canon match populates gar_flat_count).
|
||||
-- SAFETY: только CREATE OR REPLACE VIEW — идемпотентно, не деструктивно. Колонки/типы
|
||||
-- не меняются (тот же набор столбцов), меняется лишь условие в CASE sale_share_pct.
|
||||
-- Deploy order: после 144_gar_canon_addr_match.sql.
|
||||
|
||||
BEGIN;
|
||||
|
||||
CREATE OR REPLACE VIEW v_building_sale_share AS
|
||||
WITH listing_agg AS (
|
||||
SELECT l.house_id_fk AS house_id,
|
||||
count(*) FILTER (WHERE l.is_active AND l.listing_segment = 'vtorichka'::text) AS active_secondary,
|
||||
percentile_cont(0.5::double precision) WITHIN GROUP (ORDER BY (l.price_rub::double precision))
|
||||
FILTER (WHERE l.is_active AND l.listing_segment = 'vtorichka'::text AND l.price_rub IS NOT NULL) AS median_price_rub,
|
||||
percentile_cont(0.5::double precision) WITHIN GROUP (ORDER BY (l.price_per_m2::double precision))
|
||||
FILTER (WHERE l.is_active AND l.listing_segment = 'vtorichka'::text AND l.price_per_m2 IS NOT NULL) AS median_price_per_m2,
|
||||
avg(l.days_on_market)
|
||||
FILTER (WHERE l.is_active AND l.listing_segment = 'vtorichka'::text AND l.days_on_market IS NOT NULL) AS avg_days_on_market
|
||||
FROM listings l
|
||||
WHERE l.house_id_fk IS NOT NULL
|
||||
GROUP BY l.house_id_fk
|
||||
)
|
||||
SELECT h.id AS house_id,
|
||||
h.short_address,
|
||||
h.full_address,
|
||||
h.address,
|
||||
h.lat,
|
||||
h.lon,
|
||||
h.year_built,
|
||||
h.house_type,
|
||||
h.total_floors,
|
||||
h.series_name,
|
||||
h.is_emergency,
|
||||
COALESCE(h.gar_flat_count, NULLIF(h.total_units, 0), NULLIF(h.flat_count, 0)) AS flat_count_effective,
|
||||
h.gar_flat_count,
|
||||
h.gar_match_method,
|
||||
la.active_secondary,
|
||||
la.median_price_rub,
|
||||
la.median_price_per_m2,
|
||||
la.avg_days_on_market,
|
||||
CASE
|
||||
WHEN COALESCE(h.gar_flat_count, NULLIF(h.total_units, 0), NULLIF(h.flat_count, 0))
|
||||
>= GREATEST(COALESCE(h.total_floors, 0), 8)
|
||||
AND la.active_secondary <= COALESCE(h.gar_flat_count, NULLIF(h.total_units, 0), NULLIF(h.flat_count, 0))
|
||||
THEN round(100.0 * la.active_secondary::numeric
|
||||
/ COALESCE(h.gar_flat_count, NULLIF(h.total_units, 0), NULLIF(h.flat_count, 0))::numeric, 1)
|
||||
ELSE NULL::numeric
|
||||
END AS sale_share_pct
|
||||
FROM houses h
|
||||
JOIN listing_agg la ON la.house_id = h.id
|
||||
WHERE h.geom IS NOT NULL AND la.active_secondary > 0;
|
||||
|
||||
COMMENT ON VIEW v_building_sale_share IS
|
||||
'Per-building rollup вторички для «доли квартир дома в продаже» (мигр. 143; '
|
||||
'знаменатель — ГАР canon-match мигр. 144). sale_share_pct только при правдоподобном '
|
||||
'знаменателе: flat_count_effective >= GREATEST(total_floors,8) AND active<=flat_count '
|
||||
'(мигр. 145 — защита от ГАР-undercount); иначе NULL. Фильтр: geom NOT NULL AND active>0.';
|
||||
|
||||
COMMIT;
|
||||
Loading…
Add table
Reference in a new issue