loko/streetup/reporting/sql/mv_location_hierarchy.sql
2026-07-22 14:48:40 +02:00

292 lines
11 KiB
SQL

-- ============================================================
-- 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);