-- ============================================================ -- Materialized view : reporting.mv_location_hierarchy -- Scope : toutes les localisations actives de tous les types, -- avec résolution de la hiérarchie (parent → root). -- Refresh : via management command refresh_reporting_views (daily) -- -- Clé de jointure avec mv_interventions : -- mv_interventions.loc_content_type_id = mv_location_hierarchy.content_type_id -- mv_interventions.loc_object_id = mv_location_hierarchy.object_id -- -- Types de localisation couverts : -- trafficlightintersection (assets_trafficlightintersection) -- structurelocation (assets_structurelocation) — groupé par ouvrage -- itslocation (assets_itslocation) -- naturelocation (assets_naturelocation) -- publiclightingstreet (assets_publiclightingstreet) -- cleanlocation (assets_cleanlocation) -- controlcenterlocation (assets_controlcenterlocation) -- signstreet (sign_signstreet) -- ============================================================ DROP MATERIALIZED VIEW IF EXISTS reporting.mv_location_hierarchy; CREATE MATERIALIZED VIEW reporting.mv_location_hierarchy AS WITH RECURSIVE -- ── Résolution des content_type IDs (une seule fois) ─────────────────── ct (ct_id, model) AS ( SELECT id AS ct_id, model FROM django_content_type WHERE (app_label = 'assets' AND model IN ( 'trafficlightintersection', 'structurelocation', 'itslocation', 'naturelocation', 'publiclightingstreet', 'cleanlocation', 'controlcenterlocation')) OR (app_label = 'sign' AND model = 'signstreet') ), -- ── Hiérarchie récursive : ITS Locations ─────────────────────────────── its_root (id, root_id) AS ( -- Racines : localisations sans parent SELECT id, id AS root_id FROM assets_itslocation WHERE parent_location_id IS NULL -- Enfants : on remonte jusqu'à la racine UNION ALL SELECT child.id, parent.root_id FROM assets_itslocation child JOIN its_root parent ON parent.id = child.parent_location_id ), -- ── Hiérarchie récursive : Nature Locations ──────────────────────────── nature_root (id, root_id) AS ( SELECT id, id AS root_id FROM assets_naturelocation WHERE parent_location_id IS NULL UNION ALL SELECT child.id, parent.root_id FROM assets_naturelocation child JOIN nature_root parent ON parent.id = child.parent_location_id ), -- ── Hiérarchie récursive : Control Center Locations ─────────────────── cc_root (id, root_id) AS ( SELECT id, id AS root_id FROM assets_controlcenterlocation WHERE parent_location_id IS NULL UNION ALL SELECT child.id, parent.root_id FROM assets_controlcenterlocation child JOIN cc_root parent ON parent.id = child.parent_location_id ) -- ── Traffic Light Intersections ───────────────────────────────────────────── -- Niveau de regroupement : l'intersection elle-même (ou son maître si défini). SELECT (SELECT ct_id FROM ct WHERE model = 'trafficlightintersection') AS content_type_id, tli.id AS object_id, 'trafficlightintersection' AS location_type, tli.code, tli.name_fr, tli.name_nl, tli.lon, tli.lat, -- Parent : intersection maître (peut être NULL) (SELECT ct_id FROM ct WHERE model = 'trafficlightintersection') AS parent_content_type_id, tli.master_id AS parent_object_id, -- Root : soi-même (les intersections sont le niveau atomique de regroupement) (SELECT ct_id FROM ct WHERE model = 'trafficlightintersection') AS root_content_type_id, tli.id AS root_object_id, tli.code AS root_code, tli.name_fr AS root_name_fr, tli.name_nl AS root_name_nl, mun.name_fr AS municipality_name_fr, mun.name_nl AS municipality_name_nl FROM assets_trafficlightintersection tli LEFT JOIN common_municipality mun ON mun.id = tli.municipality_id UNION ALL -- ── Structure Locations ───────────────────────────────────────────────────── -- Regroupement par ouvrage (Structure) ; root = localisation principale de l'ouvrage. SELECT (SELECT ct_id FROM ct WHERE model = 'structurelocation'), sl.id, 'structurelocation', sl.code, sl.name_fr, sl.name_nl, sl.lon, sl.lat, (SELECT ct_id FROM ct WHERE model = 'structurelocation'), sl.parent_location_id, (SELECT ct_id FROM ct WHERE model = 'structurelocation'), COALESCE( (SELECT id FROM assets_structurelocation WHERE structure_id = sl.structure_id AND is_main_location = TRUE LIMIT 1), sl.id ) AS root_object_id, COALESCE(s.code, sl.code) AS root_code, COALESCE(s.name_fr, sl.name_fr) AS root_name_fr, COALESCE(s.name_nl, sl.name_nl) AS root_name_nl, NULL::VARCHAR AS municipality_name_fr, NULL::VARCHAR AS municipality_name_nl FROM assets_structurelocation sl LEFT JOIN assets_structure s ON s.id = sl.structure_id UNION ALL -- ── ITS Locations ──────────────────────────────────────────────────────────── SELECT (SELECT ct_id FROM ct WHERE model = 'itslocation'), il.id, 'itslocation', il.code, il.name_fr, il.name_nl, il.lon, il.lat, (SELECT ct_id FROM ct WHERE model = 'itslocation'), il.parent_location_id, (SELECT ct_id FROM ct WHERE model = 'itslocation'), ir.root_id, root_il.code, root_il.name_fr, root_il.name_nl, NULL::VARCHAR, NULL::VARCHAR FROM assets_itslocation il JOIN its_root ir ON ir.id = il.id JOIN assets_itslocation root_il ON root_il.id = ir.root_id UNION ALL -- ── Nature Locations ───────────────────────────────────────────────────────── SELECT (SELECT ct_id FROM ct WHERE model = 'naturelocation'), nl.id, 'naturelocation', nl.code, nl.name_fr, nl.name_nl, nl.lon, nl.lat, (SELECT ct_id FROM ct WHERE model = 'naturelocation'), nl.parent_location_id, (SELECT ct_id FROM ct WHERE model = 'naturelocation'), nr.root_id, root_nl.code, root_nl.name_fr, root_nl.name_nl, mun.name_fr, mun.name_nl FROM assets_naturelocation nl JOIN nature_root nr ON nr.id = nl.id JOIN assets_naturelocation root_nl ON root_nl.id = nr.root_id LEFT JOIN common_municipality mun ON mun.id = nl.municipality_id UNION ALL -- ── Public Lighting Streets ────────────────────────────────────────────────── SELECT (SELECT ct_id FROM ct WHERE model = 'publiclightingstreet'), pls.id, 'publiclightingstreet', pls.code, pls.name_fr, pls.name_nl, pls.lon, pls.lat, NULL::INTEGER, NULL::INTEGER, (SELECT ct_id FROM ct WHERE model = 'publiclightingstreet'), pls.id, pls.code, pls.name_fr, pls.name_nl, mun.name_fr, mun.name_nl FROM assets_publiclightingstreet pls LEFT JOIN common_municipality mun ON mun.id = pls.municipality_id UNION ALL -- ── Clean Locations ─────────────────────────────────────────────────────────── SELECT (SELECT ct_id FROM ct WHERE model = 'cleanlocation'), cl.id, 'cleanlocation', cl.code, cl.name_fr, cl.name_nl, cl.lon, cl.lat, NULL::INTEGER, NULL::INTEGER, (SELECT ct_id FROM ct WHERE model = 'cleanlocation'), cl.id, cl.code, cl.name_fr, cl.name_nl, mun.name_fr, mun.name_nl FROM assets_cleanlocation cl LEFT JOIN common_municipality mun ON mun.id = cl.municipality_id UNION ALL -- ── Control Center Locations ───────────────────────────────────────────────── SELECT (SELECT ct_id FROM ct WHERE model = 'controlcenterlocation'), ccl.id, 'controlcenterlocation', ccl.code, ccl.name_fr, ccl.name_nl, ccl.lon, ccl.lat, (SELECT ct_id FROM ct WHERE model = 'controlcenterlocation'), ccl.parent_location_id, (SELECT ct_id FROM ct WHERE model = 'controlcenterlocation'), ccr.root_id, root_ccl.code, root_ccl.name_fr, root_ccl.name_nl, NULL::VARCHAR, NULL::VARCHAR FROM assets_controlcenterlocation ccl JOIN cc_root ccr ON ccr.id = ccl.id JOIN assets_controlcenterlocation root_ccl ON root_ccl.id = ccr.root_id UNION ALL -- ── Sign Streets ───────────────────────────────────────────────────────────── SELECT (SELECT ct_id FROM ct WHERE model = 'signstreet'), ss.id, 'signstreet', ss.code, ss.name_fr, ss.name_nl, ss.lon, ss.lat, NULL::INTEGER, NULL::INTEGER, (SELECT ct_id FROM ct WHERE model = 'signstreet'), ss.id, ss.code, ss.name_fr, ss.name_nl, mun.name_fr, mun.name_nl FROM sign_signstreet ss LEFT JOIN common_municipality mun ON mun.id = ss.municipality_id WITH DATA; -- ── Index unique requis pour REFRESH MATERIALIZED VIEW CONCURRENTLY ───────── CREATE UNIQUE INDEX reporting_mv_location_hierarchy_pk ON reporting.mv_location_hierarchy (content_type_id, object_id); -- ── Index opérationnels ────────────────────────────────────────────────────── CREATE INDEX reporting_mv_location_hierarchy_type ON reporting.mv_location_hierarchy (location_type); CREATE INDEX reporting_mv_location_hierarchy_root ON reporting.mv_location_hierarchy (root_content_type_id, root_object_id);