In questo blog post risponderò al quesito posto da Giuliano su messenger 💭:

In pratica, Giuliano mi sta chiedendo come fare JOIN tabellari tra 70 vettori e non le classiche due tabelle.
Il quesito risulta apparentemente complesso, visto che normalmente una join tabellare si esegue tra due tabelle, quindi la prima cosa che viene in mente è quella di iterare il processo di join, ma in realtà la soluzione è molto più semplice; sotto descriverò diverse approcci per risolvere il quesito.
INTRO: Come fare una JOIN tabellare
A partire da due tabelle (shp001, shp002), ognuna con un campo correlato (che ha gli stessi valori in entrambe le tabelle, per esempio id), per effettuare una JOIN tabellare usando ogr2ogr e la riga di comando, lanciare questo script:
ogr2ogr -sql \
"SELECT t1.id AS id, t1.nome AS nome, t1.value AS val_shp001, t2.value AS val_shp002 \
FROM shp001 t1 JOIN './shp002.shp'.shp002 t2 \
ON t1.id=t2.id" \
./shpOUT.shp ./shp001.shp
risultato:
OSSERVAZIONI
Realizzare una JOIN tabellare è cosa semplice e veloce, ma realizzare molte JOIN consecutive non è altrettanto semplice soprattutto se volessimo iterare lo script ogr2ogr sopra descritto, quindi, occorre cambiare processo: “un probabile approccio risolutivo potrebbe essere quello di convertire i vettori (dal shp002 al shp070) in semplici tabelle CSV e fare un merge orizzontale tra tutti i file, infine, fare una sola JOIN tabellare tra il primo vettore shp001 (che conserverebbe la geometria) e il tabellone risultante dal merge precedente”. [idea di Andrea Borruso]
La conversione di formato, da vettore a tabella CSV, facilità l’unione dei file; sotto alcuni esempi su come fare la conversione e la multi-join orizzontale:
RIGA DI COMANDO
Prima soluzione ambiente bash (linux)
#!/bin/bash
#### RIFERIMENTI #####
# ogr2ogr : https://gdal.org/programs/ogr2ogr.html
# miller : https://github.com/johnkerl/miller
####################
set -x
set -e
set -u
set -o pipefail
# crea i CSV e ordina i CSV per ID
for i in *.shp; do
name=$(basename "$i" .shp)
ogr2ogr -f CSV -sql 'select id,value from '"$name"'' "$name".csv "$name".shp
mlr -I --csv sort -n id then cut -f value then rename value,value_"$name" "$name".csv
done
# unisci i CSV in un unico CSV
paste -d "," shp*.csv > all.csv
# estrai il primo shp e convertilo in CSV
primoShape=$(find ./ -iname "*.shp" -type f | head -n 1)
tmp=$(basename "$primoShape" .shp)
ogr2ogr -f CSV tmp.csv "$tmp".shp
# estrai da questo ultimo soltanto la colonna id
mlr -I --csv cut -f id then sort -n id tmp.csv
# crea il file finale
paste -d "," tmp.csv all.csv > finale.csv
# rimuove file inutili
rm tmp.csv
rm all.csv
# realizzato da Andrea Borruso
da questo script bash otterremo un unico file CSV (finale.csv) pronto per essere messo in JOIN con il primo vettore:
Seconda soluzione ambiente bash (linux)
fare un normalissimo fondi vettori, ovvero, unione verticale di tutti i vettori; successivamente, convertire l’unico vettore in file CSV; infine, convertire il file CSV da wide a long:
#!/bin/bash
#### RIFERIMENTI #####
# ogr2ogr : https://gdal.org/programs/ogr2ogr.html
# ogrmerge.py : https://gdal.org/programs/ogrmerge.html
# miller : https://github.com/johnkerl/miller
####################
# unisci in verticale gli shape
ogrmerge.py -overwrite_ds -single -src_layer_field_name layer -o merged.shp shp*.shp
# converti lo shape in CSV
ogr2ogr -f CSV merged.csv merged.shp
# converti il CSV da wide a long
mlr -I --csv reshape -s layer,value merged.csv
# cancella file inutili
rm merged.shp
rm merged.shx
rm merged.prj
rm merged.dbf
# realizzato da Andrea Borruso
da questo script bash otterremo un unico file CSV (merged.csv) pronto per essere messo in JOIN con il primo vettore (che conterrà anche la geometria):
Terza soluzione ambiente Python
usando Python e geopandas
import glob
import geopandas as gpd
files = glob.glob("../data/andrea/*.shp")
files.sort()
gdf = gpd.read_file(files[0])
gdf.rename(columns={'value':f'value_shp001'}, inplace=True)
for f in files[1:]:
name = f[f.rfind('/')+1:-4]
gdf2 = gpd.read_file(f)
new_column = f'value_{name}'
gdf2.rename(columns={'value': new_column}, inplace=True)
gdf = gdf.merge(gdf2[['id',new_column]], on='id')
In questo caso otterremo un unico vettore con tutte i campi uniti!!! (Grazie a Giovanni Pirrotta)
TUTTO con QGIS
Plugin Group Stats
Soluzione usando solo QGIS e il plugin Group Stats:
- Usare algoritmo di Processing
Fondi Vettori, per ottenere una unione verticale dei vettori; - Usando il plugin, creare una tabella Pivot;
- salvare la tabella Pivot in CSV e modificare l’intestazione;
- infine, fare una JOIN tabellare.
Plugin
Per chi ama i bottoni, ecco la soluzione definitiva e immediata, tramite Plugin per QGIS realizzato da Giulio Fattori: in INPUT (Get File:): selezionare il file (shp o gpkg), il campo correlato (Join Field:) e campo da unire (Data field:); in OUTPUT, direttamente il vettore con tutti gli attributi uniti.
Il plugin è disponibile nella repository ufficiale di QGIS, con relativa guida.
NOTE FINALI: sicuramente esistono altri approcci per risolvere il quesito (probabilmente anche tramite mapshaper), ma credo di aver proposto varie soluzioni, anche per vari ambienti e per tutti i palati: per chi ama la riga di comando fino a chi ama pigiare solo i bottoni 🙂
RIFERIMENTI
- Ricetta T’ansignari : https://tansignari.opendatasicilia.it/ricette/riga_comando/multi_join/
- ogr2ogr : https://gdal.org/programs/ogr2ogr.html
- ogrmerge.py : https://gdal.org/programs/ogrmerge.html
- Miller : https://github.com/johnkerl/miller
- Geopandas : https://geopandas.org/en/stable/
- VisiData : https://ondata.github.io/guidaVisiData/
- pyQGIS : https://docs.qgis.org/3.22/en/docs/pyqgis_developer_cookbook/index.html
- Plugin Group Stats : https://plugins.qgis.org/plugins/GroupStats/
RINGRAZIAMENTI
- Andrea Borruso
- Giovanni Pirrotta
- Giulio Fattori
- Giuliano Ramat
DATI PER TEST
I MIEI CANALI – ISCRIVITI
- Telegram : https://t.me/pigrecoinfinito
- YouTube : https://www.youtube.com/c/TotòFiandaca
Se il blog post Ti è piaciuto cliccate su ‘Mi piace’, grazie!!!
if you liked the blog post click on ‘Like’, thank you !!!








