From 77266de762870ef3e03a4b5b7f83cb0a1fe73d8a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 31 Dec 2024 10:58:03 +0000 Subject: [PATCH] =?UTF-8?q?[pre-commit.ci]=20Corrections=20automatiques=20?= =?UTF-8?q?appliqu=C3=A9es=20par=20les=20git=20hooks.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/articles/2024/2024-12-31_sql_json.md | 353 +++++++++---------- 1 file changed, 176 insertions(+), 177 deletions(-) diff --git a/content/articles/2024/2024-12-31_sql_json.md b/content/articles/2024/2024-12-31_sql_json.md index e2737e2a61..e23c120fef 100644 --- a/content/articles/2024/2024-12-31_sql_json.md +++ b/content/articles/2024/2024-12-31_sql_json.md @@ -22,7 +22,7 @@ tags: Dans le cadre d'un projet personnel, j'ai voulu stocker une bonne partie des données du recensement de l'insee dans une base PostgreSQL avec des tables multimillésimes. Problème, même au sein d'un même jeu de données, les champs peuvent changer au cours des années et celà empêche de pouvoir dégager une structure de table fixe, ce qui est assez génant vous en conviendrez. La solution ? Passer par des données semi-structurées, soit stocker ces données en json dans le champ d'une table. Cet article se veut un condensé de cet expérience. !!! warning - Ces travaux ont été réalisés avant la sortie de PostgreSQL 17 qui ajoute d'importantes fonctionnalités pour le json comme les [`JSON_TABLE`](https://doc.postgresql.fr/17/functions-json.html#FUNCTIONS-SQLJSON-TABLE), elles ne seront ici pas évoquées. + Ces travaux ont été réalisés avant la sortie de PostgreSQL 17 qui ajoute d'importantes fonctionnalités pour le json comme les [`JSON_TABLE`](https://doc.postgresql.fr/17/functions-json.html#FUNCTIONS-SQLJSON-TABLE), elles ne seront ici pas évoquées. Puisque nous allons parler de json et de données semi-structurées, je me sens dans l'obligation de commencer cet article par un avertissement. @@ -108,7 +108,7 @@ PostgreSQL est capable de stocker les données/objets au format json dans des ch ### Les index -Il est possible d'indexer un champ de type `json` / `jsonb` sur ses clés **de premier niveau** et ça se fait avec des index de type `GIN`. +Il est possible d'indexer un champ de type `json` / `jsonb` sur ses clés **de premier niveau** et ça se fait avec des index de type `GIN`. ```sql CREATE INDEX idx_tb_champjson ON tb USING gin (champ_json); @@ -135,7 +135,7 @@ BEGIN -- table listant les differentes bases insee disponibles CREATE TABLE insee.bases ( -pk_id int2 PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY +pk_id int2 PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY nom text NOT NULL ); @@ -190,14 +190,14 @@ A quoi ressemblerai la création de insee.donnees_communes si on la partitionnai ```sql BEGIN CREATE TABLE insee.donnees_communes ( - pk_id int4 GENERATED BY DEFAULT AS IDENTITY, - code_commune text NOT NULL CHECK length(code_com) = 5, - annee int2 NOT NULL, - fk_base int2 NOT NULL, - donnees jsonb NOT NULL, - UNIQUE (annee, code_commune, fk_base), - CONSTRAINT pk_donnees_communes PRIMARY KEY (pk_id, fk_base), - CONSTRAINT fk_donnees_bases FOREIGN KEY (fk_base) REFERENCES insee.bases (pk_id) ON UPDATE CASCADE ON DELETE CASCADE + pk_id int4 GENERATED BY DEFAULT AS IDENTITY, + code_commune text NOT NULL CHECK length(code_com) = 5, + annee int2 NOT NULL, + fk_base int2 NOT NULL, + donnees jsonb NOT NULL, + UNIQUE (annee, code_commune, fk_base), + CONSTRAINT pk_donnees_communes PRIMARY KEY (pk_id, fk_base), + CONSTRAINT fk_donnees_bases FOREIGN KEY (fk_base) REFERENCES insee.bases (pk_id) ON UPDATE CASCADE ON DELETE CASCADE ) PARTITION BY LIST (fk_base); CREATE TABLE insee.donnees_communes_fk_1 PARTITION OF insee.donnees_communes FOR VALUES IN (1); CREATE TABLE insee.donnees_communes_fk_2 PARTITION OF insee.donnees_communes FOR VALUES IN (2); @@ -208,7 +208,6 @@ CREATE TABLE insee.donnees_communes_fk_6 PARTITION OF insee.donnees_communes FOR END; ``` - ### Insertion de données et récupération Pour passer des données textuelles / sql vers des données encodées en json dans le champ dédié qui va bien, PostgreSQL dispose de [*quelques* fonctions](https://docs.postgresql.fr/17/functions-json.html#FUNCTIONS-JSON-PROCESSING). Nous allons utiliser la fonction `jsonb_object()` qui permet de transformer un `array` sql sous forme `clef1, valeur1, clef2, valeur2 ....` en objet `jsonb` qui n'aura qu'un niveau d'imbrication. D'autres fonctions sont disponibles pour des objets plus complexes (comme `jsonb_build_object()`). @@ -264,11 +263,11 @@ Pour injecter du json complexe dans un champs, deux solutions s'offrent à nous ```sql INSERT INTO test.test (donnees) VALUES (jsonb_object( - 'cle1', 'valeur1', - 'cle2', jsonb_array( - 'foo', 'bar', 'baz') - ) - ) + 'cle1', 'valeur1', + 'cle2', jsonb_array( + 'foo', 'bar', 'baz') + ) + ) ``` Cette insertion pourrait tout aussi bien s'écrire avec un cast d'une chaine de texte vers du jsonb, attention, la syntaxe json doit être ici respectée : @@ -282,7 +281,7 @@ Pour récupérer une valeur, on utilise la fonction `jsonb_path_query()` qui pos ```sql SELECT - jsonb_path_query(donnee, '$.cle2[1]') + jsonb_path_query(donnee, '$.cle2[1]') FROM test.test ``` @@ -317,123 +316,123 @@ Notez que si votre table temporaire possède un nom différent de "rp_population ```sql -- cte concatenant les données avec les clés et nettoyant les caractères spéciaux. WITH d AS ( - SELECT - "CODGEO", - regexp_replace('pop_p,' || "POP_P" || ', - pop_0_14_ans_p,' || "POP0014_P" || ', - pop_15_29_ans_p,' || "POP1529_P" || ', - pop_30_44_ans_p,' || "POP3044_P" || ', - pop_45_59_ans_p,' || "POP4559_P" || ', - pop_60_74_ans_p,' || "POP6074_P" || ', - pop_75_89_ans_p,' || "POP7589_P" || ', - pop_90_ans_plus_p,' || "POP90P_P" || ', - hommes_p,' || "POPH_P" || ', - hommes_0_14_ans_p,' || "H0014_P" || ', - hommes_15_29_ans_p,' || "H1529_P" || ', - hommes_30_44_ans_p,' || "H3044_P" || ', - hommes_45_59_ans_p,' || "H4559_P" || ', - hommes_60_74_ans_p,' || "H6074_P" || ', - hommes_75_89_ans_p,' || "H7589_P" || ', - hommes_90_ans_plus_p,' || "H90P_P" || ', - hommes_0_19_ans_p,' || "H0019_P" || ', - hommes_20_64_ans_p,' || "H2064_P" || ', - hommes_65_ans_plus_p,' || "H65P_P" || ', - femmes_p,' || "POPF_P" || ', - femmes_0_14_ans_p,' || "F0014_P" || ', - femmes_15_29_ans_p,' || "F1529_P" || ', - femmes_30_44_ans_p,' || "F3044_P" || ', - femmes_45_59_ans_p,' || "F4559_P" || ', - femmes_60_74_ans_p,' || "F6074_P" || ', - femmes_75_89_ans_p,' || "F7589_P" || ', - femmes_90_ans_plus_p,' || "F90P_P" || ', - femmes_0_19_ans_p,' || "F0019_P" || ', - femmes_20_64_ans_p,' || "F2064_P" || ', - femmes_65_ans_plus_p,' || "F65P_P" || ', - pop_1an_ou_plus_localisee_1an_auparavant_p,' || "POP01P_P" || ', - pop_1an_ou_plus_meme_logement_1an_auparavant_p,' || "POP01P_IRAN1_P" || ', - pop_1an_ou_plus_meme_commune_1an_auparavant_p,' || "POP01P_IRAN2_P" || ', - pop_1an_ou_plus_meme_departement_1an_auparavant_p,' || "POP01P_IRAN3_P" || ', - pop_1an_ou_plus_meme_region_1an_auparavant_p,' || "POP01P_IRAN4_P" || ', - pop_1an_ou_plus_autre_region_1an_auparavant_p,' || "POP01P_IRAN5_P" || ', - pop_1an_ou_plus_un_dom_1an_auparavant_p,' || "POP01P_IRAN6_P" || ', - pop_1an_ou_plus_hors_metropole_ou_dom_1an_auparavant_p,' || "POP01P_IRAN7_P" || ', - pop_1_14ans_autre_logement_1an_auparavant_p,' || "POP0114_IRAN2P_P" || ', - pop_1_14ans_meme_commune_1an_auparavant_p,' || "POP0114_IRAN2_P" || ', - pop_1_14ans_autre_commune_1an_auparavant_p,' || "POP0114_IRAN3P_P" || ', - pop_15_24ans_autre_logement_1an_auparavant_p,' || "POP1524_IRAN2P_P" || ', - pop_15_24ans_meme_commune_1an_auparavant_p,' || "POP1524_IRAN2_P" || ', - pop_15_24ans_autre_commune_1an_auparavant_p,' || "POP1524_IRAN3P_P" || ', - pop_25_54ans_autre_logement_1an_auparavant_p,' || "POP2554_IRAN2P_P" || ', - pop_25_54ans_meme_commune_1an_auparavant_p,' || "POP2554_IRAN2_P" || ', - pop_25_54ans_autre_commune_1an_auparavant_p,' || "POP2554_IRAN3P_P" || ', - pop_55_ou_plus_autre_logement_1an_auparavant_p,' || "POP55P_IRAN2P_P" || ', - pop_55_ou_plus_meme_commune_1an_auparavant_p,' || "POP55P_IRAN2_P" || ', - pop_55_ou_plus_autre_commune_1an_auparavant_p,' || "POP55P_IRAN3P_P" || ', - pop_15_ans_plus_c,' || "POP15P_C" || ', - agriculteurs_15_ans_plus_c,' || "POP15P_CS1_C" || ', - artisants_commercants_chefs_entreprise_15_ans_plus_c,' || "POP15P_CS2_C" || ', - cadres_prof_intel_sup_15_ans_plus_c,' || "POP15P_CS3_C" || ', - professions_intermediaires_15_ans_plus_c,' || "POP15P_CS4_C" || ', - employes_15_ans_plus_c,' || "POP15P_CS5_C" || ', - ouvriers_15_ans_plus_c,' || "POP15P_CS6_C" || ', - retraites_15_ans_plus_c,' || "POP15P_CS7_C" || ', - autres_15_ans_plus_c,' || "POP15P_CS8_C" || ', - hommes_15_ans_plus_c,' || "H15P_C" || ', - h_agriculteurs_15_ans_plus_c,' || "H15P_CS1_C" || ', - h_artisants_commercants_chefs_entreprise_15_ans_plus_c,' || "H15P_CS2_C" || ', - h_cadres_prof_intel_sup_15_ans_plus_c,' || "H15P_CS3_C" || ', - h_professions_intermediaires_15_ans_plus_c,' || "H15P_CS4_C" || ', - h_employes_15_ans_plus_c,' || "H15P_CS5_C" || ', - h_ouvriers_15_ans_plus_c,' || "H15P_CS6_C" || ', - h_retraites_15_ans_plus_c,' || "H15P_CS7_C" || ', - h_autres_15_ans_plus_c,' || "H15P_CS8_C" || ', - femmes_15_ans_plus_c,' || "F15P_C" || ', - f_agricultrices_15_ans_plus_c,' || "F15P_CS1_C" || ', - f_artisanes_commercantes_cheffes_entreprise_15_ans_plus_c,' || "F15P_CS2_C" || ', - f_cadres_prof_intel_sup_15_ans_plus_c,' || "F15P_CS3_C" || ', - f_professions_intermediaires_15_ans_plus_c,' || "F15P_CS4_C" || ', - f_employees_15_ans_plus_c,' || "F15P_CS5_C" || ', - f_ouvrieres_15_ans_plus_c,' || "F15P_CS6_C" || ', - f_retraitees_15_ans_plus_c,' || "F15P_CS7_C" || ', - f_autres_15_ans_plus_c,' || "F15P_CS8_C" || ', - population_15_24_ans_c,' || "POP1524_C" || ', - pop_15_24_ans_agriculteurs_c,' || "POP1524_CS1_C" || ', - pop_15_24_ans_artisants_commercants_chefs_entreprise_c,' || "POP1524_CS2_C" || ', - pop_15_24_ans_cadres_prof_intel_sup_c,' || "POP1524_CS3_C" || ', - pop_15_24_ans_professions_intermediaires_c,' || "POP1524_CS4_C" || ', - pop_15_24_ans_employes_c,' || "POP1524_CS5_C" || ', - pop_15_24_ans_ouvriers_c,' || "POP1524_CS6_C" || ', - pop_15_24_ans_retraites_c,' || "POP1524_CS7_C" || ', - pop_15_24_ans_autres_c,' || "POP1524_CS8_C" || ', - population_25_54_ans_c,' || "POP2554_C" || ', - pop_25_54_ans_agriculteurs_c,' || "POP2554_CS1_C" || ', - pop_25_54_ans_artisants_commercants_chefs_entreprise_c,' || "POP2554_CS2_C" || ', - pop_25_54_ans_cadres_prof_intel_sup_c,' || "POP2554_CS3_C" || ', - pop_25_54_ans_professions_intermediaires_c,' || "POP2554_CS4_C" || ', - pop_25_54_ans_employes_c,' || "POP2554_CS5_C" || ', - pop_25_54_ans_ouvriers_c,' || "POP2554_CS6_C" || ', - pop_25_54_ans_retraites_c,' || "POP2554_CS7_C" || ', - pop_25_54_ans_autres_c,' || "POP2554_CS8_C" || ', - population_55_ans_et_plus_c,' || "POP55P_C" || ', - pop_55_ans_et_plus_ans_agriculteurs_c,' || "POP55P_CS1_C" || ', - pop_55_ans_et_plus_ans_artisants_commercants_chefs_entreprise_c,' || "POP55P_CS2_C" || ', - pop_55_ans_et_plus_ans_cadres_prof_intel_sup_c,' || "POP55P_CS3_C" || ', - pop_55_ans_et_plus_ans_professions_intermediaires_c,' || "POP55P_CS4_C" || ', - pop_55_ans_et_plus_ans_employes_c,' || "POP55P_CS5_C" || ', - pop_55_ans_et_plus_ans_ouvriers_c,' || "POP55P_CS6_C" || ', - pop_55_ans_et_plus_ans_retraites_c,' || "POP55P_CS7_C" || ', - pop_55_ans_et_plus_ans_autres_c,' || "POP55P_CS8_C", - E'[\t\n\r]','','g') AS data - FROM insee.rp_population_import - ) - --- Conversion des chaines de texte en json et insertion dans la table + SELECT + "CODGEO", + regexp_replace('pop_p,' || "POP_P" || ', + pop_0_14_ans_p,' || "POP0014_P" || ', + pop_15_29_ans_p,' || "POP1529_P" || ', + pop_30_44_ans_p,' || "POP3044_P" || ', + pop_45_59_ans_p,' || "POP4559_P" || ', + pop_60_74_ans_p,' || "POP6074_P" || ', + pop_75_89_ans_p,' || "POP7589_P" || ', + pop_90_ans_plus_p,' || "POP90P_P" || ', + hommes_p,' || "POPH_P" || ', + hommes_0_14_ans_p,' || "H0014_P" || ', + hommes_15_29_ans_p,' || "H1529_P" || ', + hommes_30_44_ans_p,' || "H3044_P" || ', + hommes_45_59_ans_p,' || "H4559_P" || ', + hommes_60_74_ans_p,' || "H6074_P" || ', + hommes_75_89_ans_p,' || "H7589_P" || ', + hommes_90_ans_plus_p,' || "H90P_P" || ', + hommes_0_19_ans_p,' || "H0019_P" || ', + hommes_20_64_ans_p,' || "H2064_P" || ', + hommes_65_ans_plus_p,' || "H65P_P" || ', + femmes_p,' || "POPF_P" || ', + femmes_0_14_ans_p,' || "F0014_P" || ', + femmes_15_29_ans_p,' || "F1529_P" || ', + femmes_30_44_ans_p,' || "F3044_P" || ', + femmes_45_59_ans_p,' || "F4559_P" || ', + femmes_60_74_ans_p,' || "F6074_P" || ', + femmes_75_89_ans_p,' || "F7589_P" || ', + femmes_90_ans_plus_p,' || "F90P_P" || ', + femmes_0_19_ans_p,' || "F0019_P" || ', + femmes_20_64_ans_p,' || "F2064_P" || ', + femmes_65_ans_plus_p,' || "F65P_P" || ', + pop_1an_ou_plus_localisee_1an_auparavant_p,' || "POP01P_P" || ', + pop_1an_ou_plus_meme_logement_1an_auparavant_p,' || "POP01P_IRAN1_P" || ', + pop_1an_ou_plus_meme_commune_1an_auparavant_p,' || "POP01P_IRAN2_P" || ', + pop_1an_ou_plus_meme_departement_1an_auparavant_p,' || "POP01P_IRAN3_P" || ', + pop_1an_ou_plus_meme_region_1an_auparavant_p,' || "POP01P_IRAN4_P" || ', + pop_1an_ou_plus_autre_region_1an_auparavant_p,' || "POP01P_IRAN5_P" || ', + pop_1an_ou_plus_un_dom_1an_auparavant_p,' || "POP01P_IRAN6_P" || ', + pop_1an_ou_plus_hors_metropole_ou_dom_1an_auparavant_p,' || "POP01P_IRAN7_P" || ', + pop_1_14ans_autre_logement_1an_auparavant_p,' || "POP0114_IRAN2P_P" || ', + pop_1_14ans_meme_commune_1an_auparavant_p,' || "POP0114_IRAN2_P" || ', + pop_1_14ans_autre_commune_1an_auparavant_p,' || "POP0114_IRAN3P_P" || ', + pop_15_24ans_autre_logement_1an_auparavant_p,' || "POP1524_IRAN2P_P" || ', + pop_15_24ans_meme_commune_1an_auparavant_p,' || "POP1524_IRAN2_P" || ', + pop_15_24ans_autre_commune_1an_auparavant_p,' || "POP1524_IRAN3P_P" || ', + pop_25_54ans_autre_logement_1an_auparavant_p,' || "POP2554_IRAN2P_P" || ', + pop_25_54ans_meme_commune_1an_auparavant_p,' || "POP2554_IRAN2_P" || ', + pop_25_54ans_autre_commune_1an_auparavant_p,' || "POP2554_IRAN3P_P" || ', + pop_55_ou_plus_autre_logement_1an_auparavant_p,' || "POP55P_IRAN2P_P" || ', + pop_55_ou_plus_meme_commune_1an_auparavant_p,' || "POP55P_IRAN2_P" || ', + pop_55_ou_plus_autre_commune_1an_auparavant_p,' || "POP55P_IRAN3P_P" || ', + pop_15_ans_plus_c,' || "POP15P_C" || ', + agriculteurs_15_ans_plus_c,' || "POP15P_CS1_C" || ', + artisants_commercants_chefs_entreprise_15_ans_plus_c,' || "POP15P_CS2_C" || ', + cadres_prof_intel_sup_15_ans_plus_c,' || "POP15P_CS3_C" || ', + professions_intermediaires_15_ans_plus_c,' || "POP15P_CS4_C" || ', + employes_15_ans_plus_c,' || "POP15P_CS5_C" || ', + ouvriers_15_ans_plus_c,' || "POP15P_CS6_C" || ', + retraites_15_ans_plus_c,' || "POP15P_CS7_C" || ', + autres_15_ans_plus_c,' || "POP15P_CS8_C" || ', + hommes_15_ans_plus_c,' || "H15P_C" || ', + h_agriculteurs_15_ans_plus_c,' || "H15P_CS1_C" || ', + h_artisants_commercants_chefs_entreprise_15_ans_plus_c,' || "H15P_CS2_C" || ', + h_cadres_prof_intel_sup_15_ans_plus_c,' || "H15P_CS3_C" || ', + h_professions_intermediaires_15_ans_plus_c,' || "H15P_CS4_C" || ', + h_employes_15_ans_plus_c,' || "H15P_CS5_C" || ', + h_ouvriers_15_ans_plus_c,' || "H15P_CS6_C" || ', + h_retraites_15_ans_plus_c,' || "H15P_CS7_C" || ', + h_autres_15_ans_plus_c,' || "H15P_CS8_C" || ', + femmes_15_ans_plus_c,' || "F15P_C" || ', + f_agricultrices_15_ans_plus_c,' || "F15P_CS1_C" || ', + f_artisanes_commercantes_cheffes_entreprise_15_ans_plus_c,' || "F15P_CS2_C" || ', + f_cadres_prof_intel_sup_15_ans_plus_c,' || "F15P_CS3_C" || ', + f_professions_intermediaires_15_ans_plus_c,' || "F15P_CS4_C" || ', + f_employees_15_ans_plus_c,' || "F15P_CS5_C" || ', + f_ouvrieres_15_ans_plus_c,' || "F15P_CS6_C" || ', + f_retraitees_15_ans_plus_c,' || "F15P_CS7_C" || ', + f_autres_15_ans_plus_c,' || "F15P_CS8_C" || ', + population_15_24_ans_c,' || "POP1524_C" || ', + pop_15_24_ans_agriculteurs_c,' || "POP1524_CS1_C" || ', + pop_15_24_ans_artisants_commercants_chefs_entreprise_c,' || "POP1524_CS2_C" || ', + pop_15_24_ans_cadres_prof_intel_sup_c,' || "POP1524_CS3_C" || ', + pop_15_24_ans_professions_intermediaires_c,' || "POP1524_CS4_C" || ', + pop_15_24_ans_employes_c,' || "POP1524_CS5_C" || ', + pop_15_24_ans_ouvriers_c,' || "POP1524_CS6_C" || ', + pop_15_24_ans_retraites_c,' || "POP1524_CS7_C" || ', + pop_15_24_ans_autres_c,' || "POP1524_CS8_C" || ', + population_25_54_ans_c,' || "POP2554_C" || ', + pop_25_54_ans_agriculteurs_c,' || "POP2554_CS1_C" || ', + pop_25_54_ans_artisants_commercants_chefs_entreprise_c,' || "POP2554_CS2_C" || ', + pop_25_54_ans_cadres_prof_intel_sup_c,' || "POP2554_CS3_C" || ', + pop_25_54_ans_professions_intermediaires_c,' || "POP2554_CS4_C" || ', + pop_25_54_ans_employes_c,' || "POP2554_CS5_C" || ', + pop_25_54_ans_ouvriers_c,' || "POP2554_CS6_C" || ', + pop_25_54_ans_retraites_c,' || "POP2554_CS7_C" || ', + pop_25_54_ans_autres_c,' || "POP2554_CS8_C" || ', + population_55_ans_et_plus_c,' || "POP55P_C" || ', + pop_55_ans_et_plus_ans_agriculteurs_c,' || "POP55P_CS1_C" || ', + pop_55_ans_et_plus_ans_artisants_commercants_chefs_entreprise_c,' || "POP55P_CS2_C" || ', + pop_55_ans_et_plus_ans_cadres_prof_intel_sup_c,' || "POP55P_CS3_C" || ', + pop_55_ans_et_plus_ans_professions_intermediaires_c,' || "POP55P_CS4_C" || ', + pop_55_ans_et_plus_ans_employes_c,' || "POP55P_CS5_C" || ', + pop_55_ans_et_plus_ans_ouvriers_c,' || "POP55P_CS6_C" || ', + pop_55_ans_et_plus_ans_retraites_c,' || "POP55P_CS7_C" || ', + pop_55_ans_et_plus_ans_autres_c,' || "POP55P_CS8_C", + E'[\t\n\r]','','g') AS data + FROM insee.rp_population_import + ) + +-- Conversion des chaines de texte en json et insertion dans la table INSERT INTO insee.donnees_communes("code_commune","annee","fk_base","donnees") SELECT - "CODGEO", - 2021, - 1, - jsonb_object(string_to_array(data::text,',')) + "CODGEO", + 2021, + 1, + jsonb_object(string_to_array(data::text,',')) FROM d ORDER BY "CODGEO"; ``` @@ -467,14 +466,14 @@ Jusqu'à maintenant, nous n'avons travaillé qu'avec le volet population pour so ```sql CREATE MATERIALIZED VIEW insee.presence_clefs_annees AS SELECT - c.pk_id AS pk_id, - c.clef_json AS clef_json, - c.fk_base AS fk_base, - p.premiere AS premiere_annee_presence, - d.derniere AS derniere_annee_presence + c.pk_id AS pk_id, + c.clef_json AS clef_json, + c.fk_base AS fk_base, + p.premiere AS premiere_annee_presence, + d.derniere AS derniere_annee_presence FROM insee.correspondance_clefs_champs AS c, - LATERAL (SELECT min(annee) AS premiere FROM insee.donnees_communes WHERE fk_base = c.fk_base AND donnees ? c.clef_json) AS p, - LATERAL (SELECT max(annee) AS derniere FROM insee.donnees_communes WHERE fk_base = c.fk_base AND donnees ? c.clef_json) AS d + LATERAL (SELECT min(annee) AS premiere FROM insee.donnees_communes WHERE fk_base = c.fk_base AND donnees ? c.clef_json) AS p, + LATERAL (SELECT max(annee) AS derniere FROM insee.donnees_communes WHERE fk_base = c.fk_base AND donnees ? c.clef_json) AS d ORDER BY fk_base, clef_json; ``` @@ -488,46 +487,46 @@ Maintenant, on voudrait proposer un produit un peu plus simple d'utilisation ave CREATE MATERIALIZED VIEW insee.donnees_communes_olap AS WITH -- Sélection des codes communes - codes_com AS ( - SELECT - code_admin - FROM insee.zonages_administratifs - WHERE fk_type = 1 - ), + codes_com AS ( + SELECT + code_admin + FROM insee.zonages_administratifs + WHERE fk_type = 1 + ), -- Sélections des clefs et unnest par année - clefs AS ( - SELECT - pk_id, - generate_series(premiere_annee_presence, derniere_annee_presence,1) AS annee - FROM insee.presence_clefs_annees - ), + clefs AS ( + SELECT + pk_id, + generate_series(premiere_annee_presence, derniere_annee_presence,1) AS annee + FROM insee.presence_clefs_annees + ), -- cross join des clefs + année unnestées et des codes communaux - tc AS ( - SELECT - cc.code_admin AS code_com, - cl.annee AS annee, - cl.pk_id AS pk_id - FROM codes_com AS cc - CROSS JOIN clefs AS cl - ), + tc AS ( + SELECT + cc.code_admin AS code_com, + cl.annee AS annee, + cl.pk_id AS pk_id + FROM codes_com AS cc + CROSS JOIN clefs AS cl + ), -- Selection finale avec récupération des données - final AS ( - SELECT - tc.code_com, - tc.annee, - co.fk_base, - co.clef_json, - CASE - WHEN (d.donnees ->> clef_json) IN ('','null','s','nd') THEN NULL - ELSE ((d.donnees ->> clef_json)::real) - END AS valeur - FROM tc - JOIN - insee.donnees_communes AS d ON (tc.code_com = d.code_commune AND tc.annee = d.annee) - LEFT JOIN - insee.presence_clefs_annees AS co ON tc.pk_id = co.pk_id - ORDER BY tc.annee, co.fk_base, co.clef_json, tc.code_com - ) + final AS ( + SELECT + tc.code_com, + tc.annee, + co.fk_base, + co.clef_json, + CASE + WHEN (d.donnees ->> clef_json) IN ('','null','s','nd') THEN NULL + ELSE ((d.donnees ->> clef_json)::real) + END AS valeur + FROM tc + JOIN + insee.donnees_communes AS d ON (tc.code_com = d.code_commune AND tc.annee = d.annee) + LEFT JOIN + insee.presence_clefs_annees AS co ON tc.pk_id = co.pk_id + ORDER BY tc.annee, co.fk_base, co.clef_json, tc.code_com + ) SELECT * FROM final WHERE valeur IS NOT NULL; ```