287 lines
16 KiB
SQL
287 lines
16 KiB
SQL
-- Foreign-key constraints + helper VIEWs across DOM.RF + Rosreestr tables.
|
||
-- Idempotent: bootstraps missing dimension rows first, then ALTER TABLE ... ADD CONSTRAINT IF NOT EXISTS.
|
||
|
||
-- ─────────────────────────────────────────────────────────────────────────
|
||
-- 1. BOOTSTRAP DIMENSION TABLES
|
||
-- ─────────────────────────────────────────────────────────────────────────
|
||
|
||
-- Add row 0 = РФ to domrf_regions (used as "all-Russia" placeholder by some tables)
|
||
INSERT INTO domrf_regions (region_id, region_name, federal_district)
|
||
VALUES (0, 'Российская Федерация', '_RF')
|
||
ON CONFLICT (region_id) DO NOTHING;
|
||
|
||
-- Backfill domrf_snapshots from every snapshot_date currently used in children
|
||
INSERT INTO domrf_snapshots (snapshot_date, notes)
|
||
SELECT DISTINCT s, 'auto-backfilled by 40_relations.sql' FROM (
|
||
SELECT snapshot_date AS s FROM domrf_developers_full
|
||
UNION SELECT snapshot_date FROM domrf_escrow_banks
|
||
UNION SELECT snapshot_date FROM domrf_guaranty_regions
|
||
UNION SELECT snapshot_date FROM domrf_housing_summary
|
||
UNION SELECT snapshot_date FROM domrf_planned_commissioning
|
||
UNION SELECT snapshot_date FROM domrf_sold_out
|
||
UNION SELECT snapshot_date FROM domrf_sold_out_by_year
|
||
UNION SELECT snapshot_date FROM domrf_sold_out_by_progress
|
||
UNION SELECT snapshot_date FROM domrf_mortgage_rates
|
||
UNION SELECT snapshot_date FROM domrf_region_aggregates
|
||
UNION SELECT snapshot_date FROM domrf_flat_area_distribution
|
||
UNION SELECT snapshot_date FROM domrf_developer_aggregates
|
||
UNION SELECT snapshot_date FROM domrf_launch_top
|
||
UNION SELECT snapshot_date FROM domrf_launch_obj_class
|
||
UNION SELECT snapshot_date FROM domrf_launch_monthly
|
||
UNION SELECT snapshot_date FROM domrf_sold_ready_index
|
||
UNION SELECT snapshot_date FROM domrf_sold_ready_breakdown
|
||
UNION SELECT snapshot_date FROM domrf_sold_ready_dynamics
|
||
UNION SELECT snapshot_date FROM domrf_project_finance
|
||
UNION SELECT snapshot_date FROM domrf_commissioning
|
||
UNION SELECT snapshot_date FROM domrf_mortgage_dashboard
|
||
UNION SELECT snapshot_date FROM domrf_mortgage_details
|
||
) AS dates
|
||
ON CONFLICT (snapshot_date) DO NOTHING;
|
||
|
||
-- Helper to add a constraint only if it does not already exist
|
||
-- (PostgreSQL ≥9.6: do via DO block; idempotent)
|
||
DO $$
|
||
DECLARE
|
||
rec RECORD;
|
||
BEGIN
|
||
-- ──────────────────────────────────────────────────────────────────────
|
||
-- 2. SNAPSHOT FKs (every domrf_* with snapshot_date column)
|
||
-- ──────────────────────────────────────────────────────────────────────
|
||
FOR rec IN SELECT * FROM (VALUES
|
||
('domrf_developers_full', 'fk_snap_developers_full'),
|
||
('domrf_escrow_banks', 'fk_snap_escrow_banks'),
|
||
('domrf_guaranty_regions', 'fk_snap_guaranty_regions'),
|
||
('domrf_housing_summary', 'fk_snap_housing_summary'),
|
||
('domrf_planned_commissioning', 'fk_snap_planned_commissioning'),
|
||
('domrf_sold_out', 'fk_snap_sold_out'),
|
||
('domrf_sold_out_by_year', 'fk_snap_sold_out_by_year'),
|
||
('domrf_sold_out_by_progress', 'fk_snap_sold_out_by_progress'),
|
||
('domrf_mortgage_rates', 'fk_snap_mortgage_rates'),
|
||
('domrf_region_aggregates', 'fk_snap_region_aggregates'),
|
||
('domrf_flat_area_distribution', 'fk_snap_flat_area_distribution'),
|
||
('domrf_developer_aggregates', 'fk_snap_developer_aggregates'),
|
||
('domrf_launch_top', 'fk_snap_launch_top'),
|
||
('domrf_launch_obj_class', 'fk_snap_launch_obj_class'),
|
||
('domrf_launch_monthly', 'fk_snap_launch_monthly'),
|
||
('domrf_sold_ready_index', 'fk_snap_sold_ready_index'),
|
||
('domrf_sold_ready_breakdown', 'fk_snap_sold_ready_breakdown'),
|
||
('domrf_sold_ready_dynamics', 'fk_snap_sold_ready_dynamics'),
|
||
('domrf_project_finance', 'fk_snap_project_finance'),
|
||
('domrf_commissioning', 'fk_snap_commissioning'),
|
||
('domrf_mortgage_dashboard', 'fk_snap_mortgage_dashboard'),
|
||
('domrf_mortgage_details', 'fk_snap_mortgage_details'),
|
||
('domrf_raw_endpoints', 'fk_snap_raw_endpoints')
|
||
) AS t(tbl, cn)
|
||
LOOP
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = rec.cn
|
||
) THEN
|
||
EXECUTE format(
|
||
'ALTER TABLE %I ADD CONSTRAINT %I FOREIGN KEY (snapshot_date) REFERENCES domrf_snapshots(snapshot_date) ON UPDATE CASCADE',
|
||
rec.tbl, rec.cn
|
||
);
|
||
END IF;
|
||
END LOOP;
|
||
|
||
-- ──────────────────────────────────────────────────────────────────────
|
||
-- 3. REGION FKs (domrf_region_aggregates / flat_area_distribution / developer_aggregates → domrf_regions)
|
||
-- ──────────────────────────────────────────────────────────────────────
|
||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_region_aggregates_region') THEN
|
||
ALTER TABLE domrf_region_aggregates
|
||
ADD CONSTRAINT fk_region_aggregates_region
|
||
FOREIGN KEY (region_id) REFERENCES domrf_regions(region_id) ON UPDATE CASCADE;
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_flat_area_region') THEN
|
||
ALTER TABLE domrf_flat_area_distribution
|
||
ADD CONSTRAINT fk_flat_area_region
|
||
FOREIGN KEY (region_id) REFERENCES domrf_regions(region_id) ON UPDATE CASCADE;
|
||
END IF;
|
||
|
||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_developer_agg_region') THEN
|
||
ALTER TABLE domrf_developer_aggregates
|
||
ADD CONSTRAINT fk_developer_agg_region
|
||
FOREIGN KEY (region_id) REFERENCES domrf_regions(region_id) ON UPDATE CASCADE;
|
||
END IF;
|
||
|
||
-- ──────────────────────────────────────────────────────────────────────
|
||
-- 4. DEVELOPER FK (domrf_developer_aggregates → domrf_developers)
|
||
-- ──────────────────────────────────────────────────────────────────────
|
||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_developer_agg_developer') THEN
|
||
ALTER TABLE domrf_developer_aggregates
|
||
ADD CONSTRAINT fk_developer_agg_developer
|
||
FOREIGN KEY (developer_id) REFERENCES domrf_developers(developer_id) ON UPDATE CASCADE;
|
||
END IF;
|
||
END $$;
|
||
|
||
-- ─────────────────────────────────────────────────────────────────────────
|
||
-- 5. HELPER VIEWS
|
||
-- ─────────────────────────────────────────────────────────────────────────
|
||
|
||
-- v_region_master: одна строка на регион — все ключевые метрики на последний снапшот
|
||
DROP VIEW IF EXISTS v_region_master CASCADE;
|
||
CREATE VIEW v_region_master AS
|
||
WITH latest AS (SELECT MAX(snapshot_date) AS d FROM domrf_snapshots)
|
||
SELECT
|
||
r.region_id,
|
||
r.region_name,
|
||
r.federal_district,
|
||
-- Quartirografia totals (TOTAL row)
|
||
rta.flat_count AS total_flats,
|
||
rta.area_sqm AS total_area_sqm,
|
||
-- Sold-out (DOM.RF PDF data)
|
||
so.total_area_th_sqm AS sold_out_total_th_sqm,
|
||
so.sold_pct AS sold_out_sold_pct,
|
||
so.unsold_pct AS sold_out_unsold_pct,
|
||
-- Sold-ready breakdown (Playwright API data)
|
||
srb.square_sum AS sold_ready_square,
|
||
srb.sold_perc AS sold_ready_sold_pct,
|
||
srb.ready_perc AS sold_ready_ready_pct,
|
||
srb.sold_ready_perc AS sold_ready_balance_pct,
|
||
-- Project finance
|
||
pf.rns_cnt AS project_finance_permits,
|
||
pf.dev_cnt AS project_finance_developers,
|
||
pf.guaranty_escrow_dev_cnt AS project_finance_escrow_devs,
|
||
-- Guaranty (XLSX)
|
||
g.fz214_developers AS guaranty_fz214_devs,
|
||
g.escrow_developers AS guaranty_escrow_devs,
|
||
-- Launch (запуски новых)
|
||
(SELECT value FROM domrf_launch_top
|
||
WHERE dim_type = 'region' AND metric_type = 'app'
|
||
AND entity_id = r.region_id::text AND snapshot_date = (SELECT d FROM latest)
|
||
LIMIT 1) AS launch_app_2026_sqm,
|
||
(SELECT value FROM domrf_launch_top
|
||
WHERE dim_type = 'region' AND metric_type = 'rnv'
|
||
AND entity_id = r.region_id::text AND snapshot_date = (SELECT d FROM latest)
|
||
LIMIT 1) AS launch_rnv_2026_sqm
|
||
FROM domrf_regions r
|
||
LEFT JOIN domrf_region_aggregates rta
|
||
ON rta.region_id = r.region_id
|
||
AND rta.room_count_type = 'TOTAL'
|
||
AND rta.snapshot_date = (SELECT d FROM latest)
|
||
LEFT JOIN domrf_sold_out so
|
||
ON so.territory_name = r.region_name
|
||
AND so.snapshot_date = (SELECT MAX(snapshot_date) FROM domrf_sold_out WHERE territory_name = r.region_name)
|
||
LEFT JOIN domrf_sold_ready_breakdown srb
|
||
ON srb.entity_key = r.region_name
|
||
AND srb.chart_type = 'regionChart'
|
||
AND srb.snapshot_date = (SELECT MAX(snapshot_date) FROM domrf_sold_ready_breakdown WHERE chart_type='regionChart')
|
||
LEFT JOIN domrf_project_finance pf
|
||
ON pf.subject_name = r.region_name
|
||
AND pf.snapshot_date = (SELECT MAX(snapshot_date) FROM domrf_project_finance)
|
||
LEFT JOIN domrf_guaranty_regions g
|
||
ON g.territory_name = r.region_name
|
||
AND g.snapshot_date = (SELECT MAX(snapshot_date) FROM domrf_guaranty_regions)
|
||
WHERE r.region_id > 0
|
||
ORDER BY total_area_sqm DESC NULLS LAST;
|
||
|
||
COMMENT ON VIEW v_region_master IS
|
||
'Один срез по региону: квартирография + распроданность (DOM.РФ + sold_out PDF) + проектное финансирование + запуски/ввод 2026';
|
||
|
||
-- v_developer_master: профиль застройщика (latest snapshot)
|
||
DROP VIEW IF EXISTS v_developer_master CASCADE;
|
||
CREATE VIEW v_developer_master AS
|
||
WITH latest AS (SELECT MAX(snapshot_date) AS d FROM domrf_snapshots)
|
||
SELECT
|
||
d.developer_id,
|
||
d.developer_name,
|
||
-- Group-of-companies aggregates (from JSON dashboard)
|
||
dat.flat_count AS group_flat_count,
|
||
dat.area_sqm AS group_area_sqm,
|
||
-- Per-юрлицо реестр (XLSX)
|
||
df.area_thousand_sqm AS legal_area_th_sqm,
|
||
df.permits_count AS legal_permits,
|
||
df.houses_count AS legal_houses,
|
||
df.flats_count AS legal_flats,
|
||
df.market_share_pct AS market_share_pct,
|
||
-- Запуски / ввод 2026 (из launch_top, dim=developer)
|
||
(SELECT value FROM domrf_launch_top
|
||
WHERE dim_type='developer' AND metric_type='app'
|
||
AND entity_id = d.developer_id AND snapshot_date = (SELECT d FROM latest)
|
||
LIMIT 1) AS launch_app_2026_sqm,
|
||
(SELECT value FROM domrf_launch_top
|
||
WHERE dim_type='developer' AND metric_type='rnv'
|
||
AND entity_id = d.developer_id AND snapshot_date = (SELECT d FROM latest)
|
||
LIMIT 1) AS launch_rnv_2026_sqm,
|
||
-- Распроданность (devChart)
|
||
(SELECT square_sum FROM domrf_sold_ready_breakdown
|
||
WHERE chart_type='devChart' AND entity_key = d.developer_name
|
||
AND snapshot_date = (SELECT MAX(snapshot_date) FROM domrf_sold_ready_breakdown WHERE chart_type='devChart')
|
||
LIMIT 1) AS sold_ready_square,
|
||
(SELECT sold_perc FROM domrf_sold_ready_breakdown
|
||
WHERE chart_type='devChart' AND entity_key = d.developer_name
|
||
AND snapshot_date = (SELECT MAX(snapshot_date) FROM domrf_sold_ready_breakdown WHERE chart_type='devChart')
|
||
LIMIT 1) AS sold_ready_sold_pct
|
||
FROM domrf_developers d
|
||
LEFT JOIN domrf_developer_aggregates dat
|
||
ON dat.developer_id = d.developer_id
|
||
AND dat.room_count_type = 'TOTAL'
|
||
AND dat.snapshot_date = (SELECT d FROM latest)
|
||
LEFT JOIN domrf_developers_full df
|
||
ON df.developer_name = d.developer_name
|
||
AND df.snapshot_date = (SELECT MAX(snapshot_date) FROM domrf_developers_full WHERE developer_name = d.developer_name);
|
||
|
||
COMMENT ON VIEW v_developer_master IS
|
||
'Профиль застройщика: реестр + квартирография по комнатностям + запуски/ввод + распроданность';
|
||
|
||
-- v_rosreestr_market_by_region — срез цен сделок и застройщиков по региону
|
||
DROP VIEW IF EXISTS v_rosreestr_market_by_region CASCADE;
|
||
CREATE VIEW v_rosreestr_market_by_region AS
|
||
SELECT
|
||
r.region_id,
|
||
r.region_name,
|
||
r.federal_district,
|
||
rar.period_start_date,
|
||
rar.doc_type,
|
||
rar.deals_count,
|
||
rar.median_price_sqm AS median_rub_sqm,
|
||
rar.p10_price_sqm AS p10_rub_sqm,
|
||
rar.p90_price_sqm AS p90_rub_sqm
|
||
FROM domrf_regions r
|
||
JOIN rr_agg_region rar
|
||
ON rar.region_code = r.region_id
|
||
WHERE rar.realestate_type_code = '002001003000' -- Помещения (квартиры)
|
||
ORDER BY r.region_id, rar.period_start_date, rar.doc_type;
|
||
|
||
COMMENT ON VIEW v_rosreestr_market_by_region IS
|
||
'Цены сделок Росреестра по регионам с DOM.РФ-именами регионов (квартиры)';
|
||
|
||
-- v_market_pulse_rf — РФ-уровень summary с разных источников за last snapshot
|
||
DROP VIEW IF EXISTS v_market_pulse_rf CASCADE;
|
||
CREATE VIEW v_market_pulse_rf AS
|
||
SELECT
|
||
-- Quartirografia
|
||
(SELECT SUM(area_sqm)/1e6 FROM domrf_region_aggregates
|
||
WHERE room_count_type='TOTAL'
|
||
AND snapshot_date = (SELECT MAX(snapshot_date) FROM domrf_region_aggregates)) AS total_construction_mln_sqm,
|
||
-- Sold-ready
|
||
(SELECT square_sum/1e6 FROM domrf_sold_ready_index
|
||
ORDER BY snapshot_date DESC LIMIT 1) AS sold_ready_total_mln_sqm,
|
||
(SELECT sold_perc FROM domrf_sold_ready_index
|
||
ORDER BY snapshot_date DESC LIMIT 1) AS sold_pct,
|
||
(SELECT ready_perc FROM domrf_sold_ready_index
|
||
ORDER BY snapshot_date DESC LIMIT 1) AS ready_pct,
|
||
-- Прайс
|
||
(SELECT avg_price_per_sqm FROM domrf_sold_out
|
||
WHERE territory_name = 'Российская Федерация'
|
||
ORDER BY snapshot_date DESC LIMIT 1) AS rf_avg_price_per_sqm,
|
||
-- Ставки
|
||
(SELECT primary_rate FROM domrf_mortgage_rates
|
||
WHERE bank_name = 'Средневзвешенная'
|
||
ORDER BY snapshot_date DESC LIMIT 1) AS market_primary_rate,
|
||
(SELECT secondary_rate FROM domrf_mortgage_rates
|
||
WHERE bank_name = 'Средневзвешенная'
|
||
ORDER BY snapshot_date DESC LIMIT 1) AS market_secondary_rate,
|
||
-- Реальные ставки (по выданным кредитам)
|
||
(SELECT primary_credit_avg_rate FROM domrf_mortgage_dashboard
|
||
ORDER BY snapshot_date DESC LIMIT 1) AS actual_primary_rate,
|
||
(SELECT secondary_credit_avg_rate FROM domrf_mortgage_dashboard
|
||
ORDER BY snapshot_date DESC LIMIT 1) AS actual_secondary_rate,
|
||
-- Объём кредитования
|
||
(SELECT total_credit_count FROM domrf_mortgage_dashboard
|
||
ORDER BY snapshot_date DESC LIMIT 1) AS total_credit_count,
|
||
(SELECT total_credit_amount/1e9 FROM domrf_mortgage_dashboard
|
||
ORDER BY snapshot_date DESC LIMIT 1) AS total_credit_amount_bln_rub;
|
||
|
||
COMMENT ON VIEW v_market_pulse_rf IS
|
||
'РФ pulse: объём строительства, распроданность, средняя цена, ставки (рыночные vs реальные), объём ипотеки';
|