L’objectif de ce script est de produire un lot de données identifiant les différences entre deux millésimes de consommation d’ENAF calculée à partir d’OCS GE donnés pour un département.
En fonction du paramétrage du fichier config.yml, le script peut être exécuté pour un département de la région ou successivement pour tous les départements.
Attention : les temps de traitement sont longs dans ce dernier cas (plusieurs heures).
library(datalibaba)
library(DBI)
library(yaml)
Attention : il faut vérifier que les paramètres spécifiés dans le fichier config.yml correspondent bien à l’environnement de travail souhaité.
On récupère ensuite les paramètres suivants via le fichier config.yml :
# Charger le fichier YAML
config <- yaml::read_yaml("../config.yml")
# Récupérer la liste annee_dept et les paramètres de connexion à la base
annee_dept <- config$annee_dept
database <- config$database
ocs_ge_schema <- config$ocs_ge_schema
work_schema <- config$work_schema
prefix_table <- config$prefix_table
role <- config$role
On configure ici :
# Préfixe final incluant "diff_"
prefix_table_diff <- paste0(prefix_table, "diff_")
# Exemple : "r_consommation_enaf_ocsge_diff_"
# Construction d'une liste : département → c(year1, year2)
dept_years <- list()
for (year in names(annee_dept)) {
for (dept in annee_dept[[year]]) {
dept <- as.character(dept)
dept_years[[dept]] <- sort(c(dept_years[[dept]], as.integer(year)))
}
}
Pour chaque couple millésimes / département :
consommation_enaf entre les deux millésimes est ensuite
stockée dans une table.# Boucle : chaque département possède exactement 2 millésimes
for (dept in names(dept_years)) {
first_year <- dept_years[[dept]][1]
last_year <- dept_years[[dept]][2]
# Nom final de la table
table_name <- paste0(work_schema, ".", prefix_table_diff, first_year, "_", last_year, "_s_", dept)
# Connexion
connexion <- datalibaba::connect_to_db(db = database, user = role)
# Requête overlay
overlay_query <- sprintf(
"DROP TABLE IF EXISTS overlay;
CREATE TEMP TABLE overlay AS
SELECT
row_number() OVER () AS uid,
a.id AS id_%s,
b.id AS id_%s,
a.consommation_enaf AS conso_%s,
b.consommation_enaf AS conso_%s,
ST_Intersection(a.the_geom, b.the_geom) AS the_geom
FROM foncier_sol.r_consommation_enaf_ocsge_%s_s_%s a
JOIN foncier_sol.r_consommation_enaf_ocsge_%s_s_%s b
ON ST_Intersects(a.the_geom, b.the_geom)
WHERE NOT ST_IsEmpty(ST_Intersection(a.the_geom, b.the_geom));",
first_year, last_year,
first_year, last_year,
first_year, dept,
last_year, dept)
# Requête création table diff
create_table_query <- sprintf(
"CREATE TABLE %s AS
SELECT *
FROM overlay
WHERE conso_%s IS DISTINCT FROM conso_%s;",
table_name,
first_year, last_year )
# Exécution
DBI::dbExecute(connexion, overlay_query)
DBI::dbExecute(connexion, create_table_query)
DBI::dbDisconnect(connexion)
message(sprintf(
"Table créée : %s (département %s, années %s → %s)",
table_name, dept, first_year, last_year))
}
L’opération de recouvrement génère la plupart du temps des scories de géométrie.
Il faut donc vérifier le type de géométrie créée par la requête pour chaque enregistrement :
# Boucle de vérification
for (dept in names(dept_years)) {
first_year <- dept_years[[dept]][1]
last_year <- dept_years[[dept]][2]
# Nom complet de la table diff
table_name <- paste0(
"zz_traitements.",
prefix_table_diff, first_year, "_", last_year, "_s_", dept)
# Connexion
connexion <- datalibaba::connect_to_db(db = database, user = role)
# Requête de vérification
check_geom_query <- sprintf(
"SELECT DISTINCT ST_GeometryType(the_geom) AS geom_type
FROM %s;",
table_name)
# Exécution
geom_types <- DBI::dbGetQuery(connexion, check_geom_query)
# Déconnexion
DBI::dbDisconnect(connexion)
# Message résultat
message(sprintf(
"Types de géométrie dans %s : %s",
table_name,
paste(unique(geom_types$geom_type), collapse = ", ")
))
}
Si la vérification indique la création de de points (simples ou multi), de lignes (simples ou multi) ou de collection de géométries, les géométries concernées sont corrigées à l’aide de la requête suivante :
# Boucle de correction des géométries
for (dept in names(dept_years)) {
first_year <- dept_years[[dept]][1]
last_year <- dept_years[[dept]][2]
# Nom complet de la table diff
table_name <- paste0(
"zz_traitements.",
prefix_table_diff, first_year, "_", last_year, "_s_", dept)
# Connexion
connexion <- datalibaba::connect_to_db(db = database, user = role)
# Mise à jour des Points / LineStrings -> MultiPolygon via buffer(0)
update_point_linestring_query <- sprintf(
"UPDATE %s
SET the_geom = ST_Multi(ST_Buffer(the_geom, 0))
WHERE ST_GeometryType(the_geom) IN
('ST_LineString', 'ST_MultiLineString', 'ST_Point', 'ST_MultiPoint');",
table_name)
# Mise à jour des GeometryCollection -> extraction polygonale
update_geom_collection_query <- sprintf(
"UPDATE %s
SET the_geom = ST_Multi(ST_CollectionExtract(the_geom, 3))
WHERE ST_GeometryType(the_geom) = 'ST_GeometryCollection';",
table_name)
# Exécution des requêtes
DBI::dbExecute(connexion, update_point_linestring_query)
DBI::dbExecute(connexion, update_geom_collection_query)
# Déconnexion
DBI::dbDisconnect(connexion)
# Message résultat
message(sprintf(
"Correction géométrique effectuée pour %s",
table_name))
}
Une fois les géométries uniquement de type polygone (simple ou multi), on ajoute sur la table du différentiel par département les contraintes géomatiques suivantes :
# Boucle d’ajout des contraintes
for (dept in names(dept_years)) {
first_year <- dept_years[[dept]][1]
last_year <- dept_years[[dept]][2]
# Nom complet de la table diff
table_name <- paste0(
"zz_traitements.",
prefix_table_diff, first_year, "_", last_year, "_s_", dept)
# Connexion
connexion <- datalibaba::connect_to_db(db = database, user = role)
# Requête dynamique d'ajout des contraintes
add_constraints_query <- sprintf(
"ALTER TABLE %s
ADD CONSTRAINT enforce_dims_geom CHECK (st_ndims(the_geom) = 2),
ADD CONSTRAINT enforce_geotype_geom CHECK (
geometrytype(the_geom) = 'MULTIPOLYGON'
OR geometrytype(the_geom) = 'POLYGON'
OR the_geom IS NULL
),
ADD CONSTRAINT enforce_srid_geom CHECK (st_srid(the_geom) = 2154);",
table_name
)
# Exécution
DBI::dbExecute(connexion, add_constraints_query)
# Déconnexion
DBI::dbDisconnect(connexion)
# Message d'information
message(sprintf(
"Contraintes ajoutées sur la table : %s",
table_name))
}
On ajoute enfin un index spatial sur la géométrie afin d’optimiser le chargement de la table :
# Boucle de création d'index GIST sur the_geom
for (dept in names(dept_years)) {
first_year <- dept_years[[dept]][1]
last_year <- dept_years[[dept]][2]
# Nom complet de la table diff
table_name <- paste0(
"zz_traitements.",
prefix_table_diff, first_year, "_", last_year, "_s_", dept
)
# Nom de l’index
index_name <- paste0(
prefix_table_diff, first_year, "_", last_year, "_s_", dept, "_the_geom_idx"
)
# Connexion
connexion <- datalibaba::connect_to_db(db = database, user = role)
# Requête CREATE INDEX dynamique
create_idx_query <- sprintf(
"CREATE INDEX %s
ON %s
USING GIST(the_geom);",
index_name, table_name
)
# Exécution
DBI::dbExecute(connexion, create_idx_query)
# Déconnexion
DBI::dbDisconnect(connexion)
# Message
message(sprintf(
"Index créé : %s sur %s",
index_name, table_name))
}