Quantcast
Channel: db-ing & geodb-ing – map freely
Viewing all 20 articles
Browse latest View live

geodjango | primo approccio

0
0

GeoDjango è un add-on per Django che consente di gestire e manipolare dati geografici all’interno di un progetto django.

Questo post riassume i passi iniziale per implemntare una class geografica in una applicazione….spero di espandere il post non appena avro’ fatto qualche test ed esperienza ulteriore. Andiamo per step:

1. Creazione del db geografico (nel mio caso si tratta di un db Postgis).

Se ancora non esiste creiamo un template per i db gis (sarà molto comodo anche in futuro):

– autenticarsi come utente postgres ed entrae in un template (esempio il “template1”):

postgres@debian:/home/sit$ psql template1;

–  creare un nuovo db che chiameremo template_gis sul modello del template0;

postgres=# CREATE DATABASE template_gis template=template0;

– uscire da psql e creare il linguaggio per il db appena creato:

postgres@debian:/home/sit$ createlang plpgsql template_gis

– poi:

postgres@debian:/home/sit$ psql -f /usr/share/postgresql/8.4/contrib/postgis-1.5/postgis.sql -d template_gis

– popoliamo la tabella spatial_ref_sys:

postgres@debian:/home/sit$ psql -d template_gis -f /usr/share/postgresql/8.4/contrib/postgis-1.5/spatial_ref_sys.sql

– entrare nuovamente in un template e indicare che template_gis è un template:

postgres=# UPDATE pg_database set datistemplate=’t’ WHERE datname=’template_gis’;

– a questo punto possiamo creare il nostro db per django usando il template_gis appena creato:

postgres=# CREATE DATABASE energia_django template=template_gis OWNER sit;

– ci spostiamo all’interno del database appena creato:

postgres=# \connect energia_django

– poi è necessario dare i GRANT di SELECT sulla spatial_erf_sys e ALL sulla geometry_columns:

postgres=# GRANT SELECT on spatial_ref_sys to sit;

postgres=# grant ALL on geometry_columns to sit;

2. Configurazione del progetto django (geodjango)

Andiamo all’interno del nostro progetto django (il progetto sia chiama “energia” e una prima applicazione si chiama “manager”)

– Configurare il file settings.py modificando le impostazioni del database come segue:

DATABASES = {
    'default': {
         'ENGINE': 'django.contrib.gis.db.backends.postgis',
         'NAME': 'energia_django',
         'USER': 'sit',
     }
}

Aggiungere:

django.contrib.gis tra le INSTALLED_APPS

3. Preparazione dei dati geografici

Partiamo da dati in formato SHP (nel nostro caso si tratta di uno SHP di punti chiamto “quadri.shp”.

– creare una directory chiamata “data” all’interno della nostra applicazione:

$ mkdir manager/data

e salviamo al suo interno gli SHP relativi:

– con ogrinfo ispezioniamo lo SHP:

$ ogrinfo -so quadro.shp quadro

ottenendo una lista di dati relativi allo SHP (tra cui il numero di feature, SRS, nomi dei campi). Questo è molto importante per creare la class (nel file models.py) che andrà ad “accogliere” i dati. Definiamo quindi la class nel nostro models.py dell’applicazione.

class QuadroIlluminazione(models.Model):
 kp = models.IntegerField()
 numnuovo = models.CharField(max_length=5)
 via = models.CharField(max_length=30)
 codanagr = models.IntegerField()
 norma = models.CharField(max_length=2)
 regolato = models.CharField(max_length=2)
 contenel = models.CharField(max_length=15)
 contpote = models.CharField(max_length=20)
 elettronic = models.CharField(max_length=2)
 ncliente = models.CharField(max_length=10)
 gmrotation = models.FloatField()
 geom = models.MultiPointField(srid=3003)
 objects = models.GeoManager()
 class Meta:
 verbose_name_plural = "Quadri illuminazione pubblica"

 # Returns the string representation of the model.
 def __unicode__(self):
 return self.numnuovo

NB: attenzione all’indentazione; in questo post puo’ non essere corretta; vedere la guida di python per una corretta scrittura del codice)

Abbiamo deifinito la nuova tabella che conterrà i dati geografici con gli stessi attributi trovati nello SHO. Gli unici due campi che vengono aggiunti sono “geom” e “objects“.

– Controlliamo che tutto sia a posto prima di generare il DB con:

$ python manage.py sqlall manager

l’output è simile a questo (la parte finale):

……………..

CREATE INDEX “manager_contrattoaperturagasnaturale_utente_id” ON “manager_contrattoaperturagasnaturale” (“utente_id”);
CREATE INDEX “manager_contrattofornituragasnaturale_utente_id” ON “manager_contrattofornituragasnaturale” (“utente_id”);
SELECT AddGeometryColumn(‘manager_quadroilluminazione’, ‘geom’, 3003, ‘MULTIPOINT’, 2);
ALTER TABLE “manager_quadroilluminazione” ALTER “geom” SET NOT NULL;
CREATE INDEX “manager_quadroilluminazione_geom_id” ON “manager_quadroilluminazione” USING GIST ( “geom” GIST_GEOMETRY_OPS );COMMIT;

– a questo punto sincornizziamo il DB con:

$ python manage.py syncdb

compariranno una serie di messaggi (con la richiesta di creazione del superutente). alla fine avremo il nostro db pronto.

4. Ridefinizione del models.py

Il models.py deve essere modificato inserendo classe e dizionario. Una funzione ci viene in aiuto per automatizzare il processo:

$ python manage.py ogrinspect manager/data/quadro.shp QuadroIlluminazione –srid=3003 –mapping –multi

Questo comando produce in output la definzione della class e del dizionario necessario per il nostro layer geografico. Tale output puo’ essere copiato/incollato nel nostro models.py

5. Caricamento dei dati del database

Per il caricamento dei dati è necessario creare un modulino python per l’import. Per farlo creare un file chiamato “load.py” e salvarlo all’interno della nostra applicazione. Copiare al suo interno il seguente codice:

import os
from django.contrib.gis.utils import LayerMapping
from models import QuadroIlluminazione

quadroilluminazione_mapping = {
 'kp' : 'KP',
 'numnuovo' : 'NumNuovo',
 'via' : 'Via',
 'codanagr' : 'CodAnagr',
 'norma' : 'Norma',
 'regolato' : 'Regolato',
 'contenel' : 'ContEnel',
 'contpote' : 'ContPote',
 'elettronic' : 'Elettronic',
 'ncliente' : 'Ncliente',
 'gmrotation' : 'GMRotation',
 'geom' : 'MULTIPOINT',

}

quadroilluminazione_shp = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data/quadro.shp'))

def run(verbose=True):
 lm = LayerMapping(QuadroIlluminazione, quadroilluminazione_shp, quadroilluminazione_mapping, transform=True, encoding='iso-8859-1')
 lm.save(strict=True, verbose=verbose)

– Ora invochiamo la shell python per importare i dati mediante il modulo appena creato

$ python manage.py shell

Al prompt di python impartiamo i seguenti comandi (prima richiamiamo il modulo e poi la funzione di “load”:

>>> from manager import load
>>> load.run()

Seguirà una serie di messaggi di import (uno per ogni feature).

6. Caricamento del layer geografico

All’interno del file “admin.py” inserire le seguenti stringhe di codice:

from django.contrib.gis import admin
from manager.models import *
........
admin.site.register(QuadroIlluminazione, admin.GeoModelAdmin)

…to be continued as soon as possible



django | somma di campi

0
0

Supponiamo di avere una tabella contente i valori dei consumi energetici di un particolare dispositivo.

In particolare abbiamo inserito un campo (somma) che sarà popolato con il risultato ottenuto dalla somma di altri 4 campi. In questo modo ad ogni inserimento (Admin) di dati relativi ai primi 4 campi (rientranti nella somma) e dopo avere cliccato il punsante “Salva” o “Salva e continua le modifiche” il campo “somma” apparirà popolato con il valore somma.

Ecco un esempio di strutturazione della class nel file models.py.

class ConsumiIlluminazione(models.Model):
 """Tabella consumi illuminazione"""

 utente = models.ForeignKey(UtenteIlluminazione)
 campo1 = models.IntegerField(null=True, blank=True)
 campo2 = models.IntegerField(null=True, blank=True)
 campo3 = models.IntegerField(null=True, blank=True)
 campo4 = models.IntegerField(null=True, blank=True)
 somma = models.IntegerField(null=True, blank=True)
 def calcoloTotale(self):
  self.somma = self.campo1 + self.campo2 + self.campo3 + self.campo4
 def save(self):
  self.calcoloTotale()
  super(ConsumiIlluminazione, self).save()
 def __unicode__(self):
  return "%s" % (self.utente)
 class Meta:
  ordering = ["utente"]
  verbose_name_plural = "Consumi illuminazione"

openlite | migrazione tra database in pochi click

0
0

Il papà di SpatiaLite, Alessandro Furieri, ha lanciato un altro ottimo tool: OpenLite. Si tratta di uno strumento leggerissimo e semplice per migrare database (interi o in parte) tra SpatiaLite, PostGIS e MySQL.

E’ disponibile in forma sorgente oppure binaria per Windows ed è accompagnato da una semplice ma esaustiva guida che si trova alla stessa pagina del progetto.

Ho provato ad installarlo dai sorgenti su Ubuntu 10.10. Ecco una sisntesi dei passaggi e delle prove fatte:

– scaricare i sorgenti da qui;

– scompattare tutto in una directory di lavoro; nel mio caso in “/home/sit/src/openlite-0.0.1

– ci sono dipendenze da soddisfare: libspatialite e wxWidgets. Le installiamo via sudo apt-get install nome_pacchetti o via synaptic

– da riga di comando si accede alla directory interessata:

cd /home/sit/src/openlite-0.0.1

– lanciare in sequenza i tre canonici comandi:

  ./configure

  make

  sudo make install-strip

– a questo punto il programma è installato. Lo lanciamo da riga di comando con:

sit@dell1530:~$ openlite

– si presenta così:

OpenLite - come si presenta

la semplicità dello strumento si nota subito


– è necessario stabilire prima di tutto una connessione ad un db SQLite. Se ne esiste già uno colleghiamoci cliccando sul pulsante in alto a sx “Connecting an existing SQLite DB” e cerchiamo il DB interessato. In alternativa possiamo creare un DB nuovo cliccando sul secondo pulsante da sx “Creating a New (empty) SQLite DB”.

– in seconda battuta connettiamoci ad un atro DB. Nel mio caso ho provato con un DB PostGIS (PostgreSQL). Cliccare sull’icona con freccia azzurra e contenitore magenta “Connecting to PostgreSQL/PostGIS DBMS”. La prima volta che si tenta di connettersi ad un DB PostgreSQL viene chiedo di individuare la libreria necessaria. Nel nostro caso si tratta di “/usr/lib/libpq.so.5.2“. Questa impostazione viene salvata permanentemente ed ogni connessione successiva a DB PostgreSQ/PostGIS cercherà questa libreria. Nel caso si indicasse la libreria sbagliata viene restituito il messaggio “No PostgreSQL Client Library available … sorry
Connection impossible”. Per “sbloccare” la situazione ed impostare il percorso corretto alla libreria ci sono due alternative:

– alternativa 1 – brutale ma efficade:

– andare nella home directory
– lanciare il comando: ls -la
– dovremmo trovare un file nascosto chiamatto “.OpenLite” (è il file in cui vengono salvate le impostazioni permanenti)
– cancellare il file e ripartire.

– alternativa 2 – piu’ soft (ma non testata):

– andare nella home directory e aprire il file nascosto .OpenLite con: $ nano .OpenLite

– modificare la riga “PostgisLibraryName=libpq.so.5.2” indicando la libreria corretta.

– rilanciare openlite e ripartire.

Una volta individuata la libreria compare un popup per l’inserimento del percorso al DB e delle credenziali di accesso.

connessione a PostgreSQL

Connessione a DB PostgreSQL/PostGIS

Nella parte dx del pannello vengono elencate tutte le tabelle presenti del DB PostgreSQL. Selezionare con click sx la tabella che si vuole trasferire al DB SQLite e poi click dx. Compare un menù contenstuale: scegliere la voce “Select for data transfer”. Poi click dx sullo schema che contiene la tabella in questione (nel nostro caso “public“) altrimenti non è possibile avviare il tarsferimento. Fatto questo verrà abilitato un nuovo pulsante “Start data transfer” che si trova a sx del pulsante “About…”.

– Click sul pulsante indicato.

– Fatto: in questo modo avviene il trasferimento della tabella in questione al DB SQLite che comparirà dopo qualche secondo (a seconda delle dimensioni) nella parte sx del pannello.

La tabella "areacirc" è stata trasferita con successo


array_to_string in Postgresql ovvero il problema della “battaglia navale”

0
0

Premetto come per ogni post su questo blog che quanto scrivo è frutto di tentativi e ricerche per risolvere un problema pratico che di volta in volta mi si presenta. Non è detto quindi che sia il modo migliore ed il più elegante; ogni feedback e/o consiglio è pertanto graditissimo.

Parto dall’inizio: dispongo di un grafo stradale (stradario comunale) archiviato in db Postgresql con estensione spaziale Postgis. La tabella contenente gli archi stradali si chiama “grafo_new”; in essa ogni arco di strada è spezzato all’intersezione con altri tratti. Questo comporta che una strada denomimata “Via Roma” sia composta da tanti archi. Inoltre il db contiene una griglia regolare di passo quadrato che identifica i quadranti del territorio comunale. Il problema da risolvere è: “Come faccio ad ottenere un elenco delle strade (in ordine alfabetico) che indichi anche il quadrante o i quadrantiall’interno dei quali la strada ricade”. Mi ricorda moltissimo il funzionamento della battaglia navale quando per colpire una nave avversaria di indicavano le coordinate: A7: acqua; B5: colpito; B6: colpito e affondato.

Un po’ come fa l’ottimo servizio maposmatic (http://www.maposmatic.org)

Ecco i passaggi che ho seguito:

1. creazione di una view in postgres che aggrega tutti i tratti di via con lo stesso nome:

#= CREATE VIEW view_grafo_union AS SELECT nome, ele_desc, ele_tipo, gid, ST_Multi(ST_Union(f.the_geom)) AS the_geom FROM grafo_new AS f GROUP BY nome ORDER BY nome;

2.creazione di una seconda view di intersezione spaziale tra il grafo e la griglia di quadranti:

#= CREATE VIEW view_grafo_union_quadrante AS SELECT ST_Intersection(r.the-geom, m.the_geom) AS intersection_geom, m.codice, r.nome FROM view_grafo_union AS r, quadrante_stradario AS m WHERE ST_Intersects(r.the_geom, m.the_geom);

3. Creazione di una query “array_to_string” che  fornisca l’elenco di tutti i quadranti di instersezione per ogni tratto di strada:

#= SELECT DISTINCT a.nome, array_to_string(array(SELECT codice FROM view_grafo_union_quadrante AS b WHERE b.nome = a.nome),’,’) FROM view_grafo_union_quadrante AS a ORDER BY nome;

Per salvare il risultato dell’ultima query su un file basta impartire prima della query il seguente comando:

#= \o /percorso/al/file/di/output.csv

Il CSV potrà poi essere aperto e gestito con Calc  o altro editor di testo.

To be continued con snapshot e altri dettagli….

 


Postgresql | Postgis | modificare i valori dei campi di una vista

0
0

Lavorando con Postgresql|Postgis mi capita spesso di avere delle tavole come viste “View” ottenute dal join di una tabella geomerica e di una tabella non-geometrica. Esempio: la tabella geometrica contiene poligoni (edifici) con un campo chiave (es= scheda); la tabella alfanumerica contiene tutti i dati relativi a quegli edifici + un campo chiave “scheda” come la prima.

Questo perché, in un lavoro svolto, un utente si occupava di gestire la parte geometrica (mediante QGIS) mentre un altro utente caricava i dati alfanumerici relativi ad un rilievo di edifici mediante interfaccia web (via PHP).

In un secondo momento quindi è stata creata una join fra le due tabelle in modo da generare tavole tematiche sulle condizioni e sull’uso di quegli edifici.

Ecco la View creata (siano “schede” e “schede_nogeom” rispettivamente la tabella geometrica e non-geometrica)

=> CREATE VIEW schede_cartogr AS SELECT scheda_nogeom.grado, scheda_nogeom.altezza, scheda_nogeom.volume, scheda_nogeom.piani, scheda_nogeom.note, scheda_nogeom.stcontetto, scheda_nogeom.punttetto, scheda_nogeom.stconprosp, scheda_nogeom.puntprosp, scheda_nogeom.stconserr, scheda_nogeom.puntserr, scheda_nogeom.stconsolai, scheda_nogeom.puntsolai, scheda_nogeom.stconmurat, scheda_nogeom.stcompl, scheda_nogeom.puntcompl, scheda_nogeom.d_uso_pint, scheda_nogeom.d_uso_pt, scheda_nogeom.d_uso_p1, scheda_nogeom.d_uso_p2, scheda_nogeom.d_uso_p3, scheda_nogeom.d_uso_p4, scheda_nogeom.d_uso_p5, scheda_nogeom.d_uso_compl, scheda_nogeom.d_uso_progetto, scheda_nogeom.d_uso_comp_grafica, scheda_nogeom.essenze_arboree, scheda_nogeom.emerg_arch, scheda_nogeom.h_pint, scheda_nogeom.h_pt, scheda_nogeom.h_p1, scheda_nogeom.h_p2, scheda_nogeom.h_p3, scheda_nogeom.h_p4, scheda_nogeom.h_p5, scheda_nogeom.vol_pint, scheda_nogeom.vol_pt, scheda_nogeom.vol_p1, scheda_nogeom.vol_p2, scheda_nogeom.vol_p3, scheda_nogeom.vol_p4, scheda_nogeom.vol_p5, scheda.area_gis, scheda_nogeom.foto1, scheda_nogeom.estratto_cartografico, scheda_nogeom.vol_residenza, scheda_nogeom.vol_comm_dir, scheda_nogeom.vol_artigianale, scheda_nogeom.vol_pubblico, scheda_nogeom.vol_misto, scheda_nogeom.puntmurat, scheda_nogeom.d_uso_vigente, scheda.gid, scheda.the_geom, scheda.scheda FROM scheda JOIN scheda_nogeom ON scheda.scheda::text = scheda_nogeom.scheda::text;

– Caricando questa vista in QGIS riusciamo quindi a consultare geometrie e tutti i valori colelgati. Ma se ad un certo punto voglio modificare un valore o alcuni valori della tabella? Abilitando l’editing sul layer “schede_cartogr” vediamo che possiamo modificare i valori ma al momento del salvataggio veniamo avvisati che non è possibile. Ci viene allora in aiuto la creazione di un RULE con istruzione “DO INSTEAD” in Postgresql . In sostanza si tratta di una regola che consente di modificare la (o le) tabelle origine agendo sulla vista.

In generale la sintassi è la seguente:

>= CREATE RULE nome_rule_da_creare AS ON UPDATE TO nome_della_view DO INSTEAD UPDATE nome_tabella_origine SET nome_campo=NEW.nome_campo WHERE campo_chiave=NEW.campo_chiave;

Ecco la definizione del RULE che ho usato:

=>CREATE RULE update_grado_schede_cartogr AS ON UPDATE TO schede_cartogr DO INSTEAD UPDATE scheda_nogeom SET grado=NEW.grado WHERE scheda=NEW.scheda;

D’ora in avanti possiamo modificare da QGIS il valore del campo “grado“; verrà aggiornato di conseguenza il valore della tabella originale.


postgresql | qualche tips, qualche tricks

0
0

Posto alcuni comandi pgsql che ho avuto modo di usare di recente dovendo maneggiare i formati date di Postgresql. Li metto cosi’ in ordine sparso e premetto che fanno riferimento ad un database usato per la gestione dei consumi energetici di impianti di illuminazione; pertanto alcuni commenti (personali) fanno riferimento a questo tipo di lavoro. Tuttavia vanno benissimo per qualsiasi altro db.

Sia data una tabella “tbl01” che contiene un campo “anno” come stringa, “data01”, “data02”, “data03”, “data04” campi in formato date, “consumo_anno” come integer :

# comando SELECT per recuperare il valore del campo “anno” sul quale faremo le nostre operazioni:

mydb=# SELECT anno FROM tbl01 WHERE id=4;
 anno
——
 2010
(1 row)

Come si puo’ vedere si tratta di un campo varchar di 4 caratteri.

# comando SELECT che converte in numero (attualmente in formato testo) il campo “anno” della tabella “tbl01”:

mydb=# SELECT to_number(anno, ‘9999’) FROM tbl01 WHERE id=4;
 to_number
———–
      2010
(1 row)

# comando SELECT per convertire in numero il campo “anno” e togliere 1:

mydb=# SELECT to_number(anno, ‘9999’)-1 FROM tbl01;
 ?column?
———-
     2009
     2009
     2008
     2009
(4 rows)

# comando per convertire in data nel formato YYYYMMDD il valore del campo “anno”:

mydb=# SELECT to_date(anno,’YYYYMMDD’) FROM tbl01 WHERE id=4;
  to_date   
————
 2010-01-01
(1 row)

# calcolo del 31 dicembre dell’anno precedente a quello in oggetto (con riferimento al campo “anno”):

mydb=# SELECT to_date(anno,’YYYYMMDD’)-1 FROM tbl01;
  ?column?  
————
 2009-12-31
 2009-12-31
 2008-12-31
 2009-12-31
(4 rows)

# comando per calcolare la differenza tra una data chiamata “data1” (inizio anno) e il 31 dicembre dell’anno precedente (giorni in eccesso inizio anno): siano data0=2008-12-29, data1=2009-01-12, data2=2009-12-31, data3=2009-12-31.

mydb=# SELECT data1-(to_date(anno,’YYYYMMDD’)-1) FROM tbl01 WHERE id=4;
 ?column?
———-
       12
(1 row)

# comando per calcolare la differenza tra il 31 dicembre dell’anno precedente e la prima data “data0” (giorni in difetto inizio anno):

mydb=# SELECT (to_date(anno,’YYYYMMDD’)-1)-data0 FROM tbl01 WHERE id=4;
 ?column?
———-
        2
(1 row)

# comando per calcolare la differenza tra “data3” e il 31 dicembre dell’anno in corso (giorni in eccesso fine anno):

mydb=# SELECT data3-(to_date(anno,’YYYYMMDD’)+364) FROM tbl01 WHERE id=4;
 ?column?
———-
        0
(1 row)

# comando per calcolare la differenza tra il 31 dicembre dell’anno in corso e la “data2” (giorni in difetto fine anno):

mydb=# SELECT (to_date(anno,’YYYYMMDD’)+364)-data2 FROM tbl01 WHERE id=4;
 ?column?
———-
        0
(1 row)

===========================================================================

Supponiamo di avere due tabelle in relazione 1 a molti (tabella “a” e tabella “b”) con campo di collegamento (“id” della tabella “a” si collega a a_id della tabella “b”). Se vogliamo recuperare valori da entrambe le tabelle:

mydb=# SELECT a.campo1, b.campo2 FROM a,b WHERE a.id=b.a_id AND campo3=valore ORDER BY id;

===========================================================================

Quella che segue e’ una query su una tabella cosi’ strutturata:

id integer
utente_id integer
data_lettura0 date
energia_attiva_kwh_fase0_l0 numeric(10,2)
energia_attiva_kwh_fase1_l0 numeric(10,2)
energia_attiva_kwh_fase2_l0 numeric(10,2)
energia_attiva_kwh_fase3_l0 numeric(10,2)
totale_energia_attiva_kwh_l0 numeric(12,2)
data_lettura1 date
energia_attiva_kwh_fase0_l1 numeric(10,2)
energia_attiva_kwh_fase1_l1 numeric(10,2)
energia_attiva_kwh_fase2_l1 numeric(10,2)
energia_attiva_kwh_fase3_l1 numeric(10,2)
totale_energia_attiva_kwh_l1 numeric(12,2)
data_lettura2 date
energia_attiva_kwh_fase0_l2 numeric(10,2)
energia_attiva_kwh_fase1_l2 numeric(10,2)
energia_attiva_kwh_fase2_l2 numeric(10,2)
energia_attiva_kwh_fase3_l2 numeric(10,2)
totale_energia_attiva_kwh_l2 numeric(12,2)
data_lettura3 date
energia_attiva_kwh_fase0_l3 numeric(10,2)
energia_attiva_kwh_fase1_l3 numeric(10,2)
energia_attiva_kwh_fase2_l3 numeric(10,2)
energia_attiva_kwh_fase3_l3 numeric(10,2)
totale_energia_attiva_kwh_l3 numeric(12,2)
anno character varying(4)
inizio_anno date
fine_anno date
consumo_anno integer

# query per aggiornare la tabella delle letture (in un db che contiene le letture dei consumi di contatori elettrici) calcolando il consumo_anno nel caso in cui data_lettura0!=data_lettura1 per l’anno=’2009′:

energia_django=> UPDATE manager_letturailluminazione SET consumo_anno=(totale_energia_attiva_kwh_l3-totale_energia_attiva_kwh_l1)+((totale_energia_attiva_kwh_l1-totale_energia_attiva_kwh_l0)/(data_lettura1-data_lettura0)*(data_lettura1-(to_date(anno,’YYYYMMDD’)-1)))-((totale_energia_attiva_kwh_l1-totale_energia_attiva_kwh_l0)/(data_lettura1-data_lettura0)*(data_lettura3-(to_date(anno,’YYYYMMDD’)+364)))  WHERE anno=’2009′ AND data_lettura0!=data_lettura1;

id integer

Da Postgresql 8.3 e Postgis 1.3.3 a Posgresql 8.4.11 e Postgis1.5.1 su Debian stable

0
0

Con questo post volevo tenere traccia della procedura di aggiornamento e migrazione dati da Postgresql 8.3 e Postgis 1.3.3 a Posgresql 8.4.11 e Postgis1.5.1.

Ho seguito questa utilissima pagina wiki

Sul nostro server “girano” attualmente Postgresql 8.3 e Postgis 1.3.3.

1- Facciamo dapprima il backup dei database presenti (il comando va lanciato per ogni db presente nel cluster).

$ PGUSER=postgres pg_dump -Fc nome_db > /percorso/alla/dir/di/dump/nome_db.dmp

NB: pg_dump con l’opzione -Fc crea un archivio compresso (un tar compresso con gzip, ovvero un tar.gz).

Nel caso si trattasse di db non spaziale e’ sufficiente dare:

$ PGUSER=postgres pg_dump -c nome_db > /percorso/alla/dir/di/dump/nome_db.sql

2- Stoppiamo Postgresql-8.3 (come root):

# /etc/init.d/postgesql stop 8.3

3- Installiamo Postgresql-8.4 e Postgis-1.5

# aptitude install postgresql-8.4 postgresql-8.4-postgis

A questo punto (non ricordo purtroppo tutte le fasi che ho percorso) al comando di stop de nuovo postgresql-8-4 compariva un errore. Ho provato a reinstallarlo ma a questo punto ottengo:

# Error: move_conffile: required configuration file /var/lib/postgresql/8.4/main/postgresql.conf does not exists.

Decido allora di reinstallare tutto ma succede il fattaccio. Non si riesce piu’ a lanciare postgresql-8-3. Il messaggio d’errore diceva che non esiste piu’ la directory “/var/lib/postgresql/8.3/main” panic…..praticamente mi e’ sparito tutto il cluster di postgresql-8.3, fumato!

Ok, pero’ i backup li ho e decido di fare un purge profondo prima di ripartire. Cerco tutti i pacchetti relativi a Postgresql.

# dpkg -l | grep postg

e rimuovo tutto con:

# aptitude purge postgresql-8.3 postgresq-8.4 postgresql-client-8.3 postgresql-client-8.4 postgresql-client-common postgresql-common postgresql

Rimuovo anche tutte le directory di sistema:

# rm -r /etc/postgresql/

# rm -r /etc/postgresql-common/

# rm -r /var/lib/postgresql/

poi togliamo manualmente l’utente “postgres” dal file “/etc/passwd” (mediante “# nano /etc/passwd” e modificando il file eliminado la riga di interesse).

Quindi reinstallo tutto con:

# aptitude install postgresql-8.4 postgresql-8.4-postgis (che si tira dietro anche tutte le dipendenze del caso)

A questo punto possiamo recuperare i dump fatti. Per fare questo ci viene in aiuto uno script in perl che si installa con postgis-1.5 (new_postgis_restore.pl).

Prima si devono ricreare i database vuoti (con lo stesso nome di quello di partenza). Essendo tutti db spaziali creiamo dapprima un template spaziale che chiamiamo “template_gis” e lo useremo poi per creare ogni db.

Come utente postgres creiamo anche gli utenti dei db stessi:

$ su

# su postgres

(come utente postgres) # psql template1; (si entra in un db qualsiasi per creare gli utenti)

=# CREATE USER nome_utente WITH PASSWORD ‘secret’ CREATEDB CREATEUSER;

Creo il nuovo database che diventaera’ il template (sempre come utente postgres):

=# CREATE DATABASE template_gis template=template0;

Usciamo dal db (<CTRL>d) e (sempre come utente postgres) importiamo in esso le funzioni spaziali:

# psql -f /usr/share/postgresql/8.4/contrib/postgis-1.5/postgis.sql -d template_gis

poi

# psql -d template_gis -f /usr/share/postgresql/8.4/contrib/postgis-1.5/spatial_ref_sys.sql

A questo punto rientriamo in template1:

# psql template1;

e facciamo in modo che il nuovo db sia un template usabile in futuro:

# UPDATE pg_database SET datistemplate=’t’ WHERE datname=’template_gis’;

ok, ora possiamo creare tutti i nostri db in base a questo template.

# CREATE DATABASE nome_db template=template_gis OWNER nome_utente; (questo va fattoper ogni db)

Quindi popoliamo i db con lo script perl citato prima (come utente normale):

$ /usr/share/postgresql/8.4/utils/new_postgis_restore.pl  /percorso/alla/dir/di/dump/nome_db.dmp | psql nome_db

Vedremo scorrere sul terminale una serie di istruzioni (il db si sta popolando). Fatto.

Alla fine (nel mio caso) ricordarsi di modificare i file “/etc/postgresql/8.4/main/postgresql.conf” e “/etc/postgresql/8.4/main/pg_hba.conf”.

Per il primo decommentare la riga relativa a “listen_addresses” e inserire l’asterisco al posto di “localhost” come riportato:

#——————————————————————————
# CONNECTIONS AND AUTHENTICATION
#——————————————————————————

# – Connection Settings –

listen_addresses = ‘*’                  # what IP address(es) to listen on;

………………

Per il secondo (nella parte finale del file):

# Database administrative login by UNIX sockets
local   all         postgres                          ident

# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD

# “local” is for Unix domain socket connections only
local   all         all                               trust
# IPv4 local connections:
host    all         all         127.0.0.1/32          trust
host    all         all         0.0.0.0/0             trust
# IPv6 local connections:
host    all         all         ::1/128               trust

altrimenti non sono consentiti connessioni da altri client (nel primo file) e l’esecuzione di pg_dumpall (nel secondo file)



qualche tips su django

0
0

Rimozione django

Per rimuovere django installato da sorgenti (nel caso si voglia installare una versione piu’ recente, per esempio) basta trovare la directory “django” e cancellarla. Per trovarla impartire il comando:

sit@debian:~$ python -c “import sys; sys.path = sys.path[1:]; import django; print(django.__path__)”

che nel mio caso restituisce:

[‘/usr/lib/pymodules/python2.6/django’]

MD_PYTHON ERROR in django

Dopo un blocco inaspettato del server (durante un processo di rsync) il gestionale django installato riportava il seguente errore:

MOD_PYTHON ERROR

…………..

…………..

Import Error: Could not import settings ‘my_app.settings’ (Is it on sys.psth? Does it have syntax error?): No module named myapp.settings

Dopo avere cercato in rete ho trovato che la causa di questo messaggio potrebbe essere:

– file di configurazione di apache errato;

– sys.path sbagliato;

– permessi non corretti su cartelle e files del progetto (permessi che inibiscono all’utente www-data di leggere i file di settings);

– bug nel codice django.

Prima di procedere ho provato a replicare l’aplicativo sul portatile (compreso db postgresql colllegato) e tutto funzionava a modino (NB: stesso SO Debian stable).

Quindi ho confrotato il file di configurazione di apache (/etc/apache2/apache2.conf”) e sono identici; quindi il problema non sta li;

ho confrontato il sys.path delle due macchine: per farlo ho lanciato una shell python, poi:

>>> import os, sys

>>> print sys.path

ed i risultati sono identici: quindi anche la seconda ipotesi e’ scartata.

Anticipo che il bug nel codice django e’ da escludere a priori visto che sul portatile gira senza problemi. Rimangono da verificare i permessi sulle cartelle del progetto.

Infatti confrontando i listati di “ls -l” sulle due macchine si nota che la directory “/home/user/” ha dei permessi differenti (nel server e’ inibita la lettura a tutti. Molto probabilmente durnate l’operazione di rsync lanciato da root ha modificato i diritti di accesso durante; il blocco del server causato da un down temporaneo della rete ha messo in lock anche le directory interessate). Cambiando questa impostazione con:

$ chmod 751 -R /home/user/

tutto e’ andato a posto



slony | replicare db postgresql (postgis)

0
0

Ho provato a buttarmi (finalmente dico io) su Slony. Si tratta di un sistema per replicare uno o più database da un server postgresql su un altro o piu’ server (anche remoti).

Ho fatto un piccolo test (per ora) cercando di replicare il db spaziale (con estensione postgis) della carta tecnica regionale numerica su un altro server.

Su entrambi i server gira Debian stable (ad oggi “squeeze”) ed hanno rispettivamente gli IP: 192.168.1.71 e 100.0.4.231.

Creiamo il database (vuoto) sul server slave con il comando:

$ su

# su postgres

# psql

=# CREATE DATABASE ctr_new_slave OWNER sit template=template_gis;

e lo strutturiamo come “ctr_new” (db master):

$ pg_dump -s -U postgres -h localhost ctr_new | psql -U postgres -h 100.0.4.71 ctr_new_slave

Quest’ultimo comando è stato impartito dal server master.

Installare slony via apt-get:

# apt-get install slony1-2-bin postgresql-8.4-slony1-2

Il database (già presente) deve avere abilitato il linguaggio procedurale plpgsql. Essendo un db creato mediante un “template_gis” che già incorpora questo linguaggio non ho dovuto fare niente. In caso di nuovo db ricordarsi invece di abilitarlo con:

(come utente postgres) # createlang plpgsql nome_db

Una prerogativa per il funzionamento di slony è che ogni tabella del db abbia una chiave primaria (notare che possono essere replicate anche solo alcune tabelle specificandole nel file di configurazione che vedremo dopo).

Configurazione degli script altperl

Ci sono diversi modi per configurare e manovrare slony: in questo esempio useremo gli script altperl (si tratta di script in perl appunto).

ci spostiamo della directory “/etc/slony/” e copiamo al suo interno il file di configurazione di esempio che si trova in “/usr/share/doc/slony1-2-bin/examples/slon_tools.conf-sample.gz” (dopo averlo decompresso e averne fatto una copia chiamata slon_tools.conf)

(come root):

# cd /etc/slony

# cp /usr/share/doc/slony1-2-bin/examples/slon_tools.conf .

modifichiamo il file con nano:

# nano slon_tools.conf

riporto il file:

======================================================

# $Id: slon_tools.conf-sample,v 1.8.2.4 2009-08-17 22:21:38 devrim Exp $
# Author: Christopher Browne
# Copyright 2004-2009 Afilias Canada
# Revised extensively by Steve Simms

# Keeping the following three lines for backwards compatibility in
# case this gets incorporated into a 1.0.6 release.
#
# TODO: The scripts should check for an environment variable
# containing the location of a configuration file.  That would
# simplify this configuration file and allow Slony-I tools to still work
# in situations where it doesn’t exist.
#
if ($ENV{“SLONYNODES”}) {
    require $ENV{“SLONYNODES”};
} else {

    # The name of the replication cluster.  This will be used to
    # create a schema named _$CLUSTER_NAME in the database which will
    # contain Slony-related data.
    $CLUSTER_NAME = ‘replication’;

    # The directory where Slony should record log messages.  This
    # directory will need to be writable by the user that invokes
    # Slony.
    $LOGDIR = ‘/var/log/slony1’;

    # SYNC check interval (slon -s option)
    # $SYNC_CHECK_INTERVAL = 1000;

    # Which node is the default master for all sets?
    $MASTERNODE = 1;

    # Which debugging level to use?  [0-4]
    $DEBUGLEVEL = 2;

    # Include add_node lines for each node in the cluster.  Be sure to
    # use host names that will resolve properly on all nodes
    # (i.e. only use ‘localhost’ if all nodes are on the same host).
    # Also, note that the user must be a superuser account.

    add_node(node     => 1,
         host     => ‘192.168.1.71’,
         dbname   => ‘ctr_new’,
         port     => 5432,
         user     => ‘postgres’,
             password => ”);

    add_node(node     => 2,
         host     => ‘100.0.4.71’,
         dbname   => ‘ctr_new_slave’,
         port     => 5432,
         user     => ‘postgres’,
             password => ”);

}

# The $SLONY_SETS variable contains information about all of the sets
# in your cluster.

$SLONY_SETS = {

    # A unique name for the set
    “set1” => {

    # The set_id, also unique
    “set_id” => 1,

    # Uncomment the following line to change the origin
    # (a.k.a. master) for the set.  The default is $MASTERNODE.
    #
    # “origin” => 1,

    # If this is set to 1, table and sequence names will be folded to lower-case
    # to match the way that PostgreSQL handles unquoted names.
    # For example, CREATE TABLE ACCOUNT(…) actually turns into CREATE TABLE account(…);
    # unless you put quotes around the table name
    # Slony always quotes object names, so you may get a mis-match between the table-name
    # as PostgreSQL understands it, and as Slony represents it.
    # default value is 0
    #
    # foldCase => 0,

    # The first ID to use for tables and sequences that are added
    # to the replication cluster.  This must be unique across the
    # cluster.
    #
    # TODO: This should be determined automatically, which can be
    # done fairly easily in most cases using psql.  create_set
    # should derive it, and give an option to override it with a
    # specific value.
    “table_id”    => 1,
    “sequence_id” => 1,

    # This array contains a list of tables that already have
    # primary keys.
        “pkeyedtables” => [
               ‘public.aree_ter’,
               ‘public.astefer’,
               ‘public.asteflu’,
               ‘public.astevia’,
               ‘public.cam_fabb’,
               ‘public.curve’,
               ‘public.discont’,
               ‘public.ele_div’,
               ‘public.err_l’,
               ‘public.fabbr_l’,
               ‘public.fabbric’,
               ‘public.ferrovie’,
               ‘public.geometry_columns’,
               ‘public.idrogr_a’,
               ‘public.idrograf’,
               ‘public.infras_a’,
               ‘public.infrastr’,
               ‘public.inquadra’,
               ‘public.lim_amm’,
               ‘public.limamm_a’,
               ‘public.nodofer’,
               ‘public.nodoflu’,
               ‘public.nodovia’,
               ‘public.opere’,
               ‘public.punti_q’,
               ‘public.sim_disc’,
               ‘public.sim_elem’,
               ‘public.sim_fabb’,
               ‘public.sim_idro’,
               ‘public.sim_infr’,
               ‘public.sim_oper’,
               ‘public.sim_vege’,
               ‘public.sim_viab’,
               ‘public.spatial_ref_sys’,
               ‘public.testi’,
               ‘public.veget_a’,
               ‘public.vegetaz’,
               ‘public.viab_a’,
               ‘public.viabilit’,
               ],

    # For tables that have unique not null keys, but no primary
    # key, enter their names and indexes here.
    #”keyedtables” => {
    #    ‘table3’ => ‘index_on_table3’,
    #    ‘table4’ => ‘index_on_table4’,
    #},

    # If a table does not have a suitable key or set of keys that
    # can act as a primary key, Slony can add one.
    #
    # Note: The Slony development team does not recomment this
    # approach — you should create your own primary keys instead.
    # “serialtables” => [“table5”],

    # Sequences that need to be replicated should be entered here.
    #”sequences” => [‘sequence1’,
    #        ‘sequence2’,
    #        ],
    },

};

# Keeping the following three lines for backwards compatibility in
# case this gets incorporated into a 1.0.6 release.
#
# TODO: The scripts should check for an environment variable
# containing the location of a configuration file.  That would
# simplify this configuration file and allow Slony tools to still work
# in situations where it doesn’t exist.
#
if ($ENV{“SLONYSET”}) {
    require $ENV{“SLONYSET”};
}

# Please do not add or change anything below this point.
1;

======================================================

Ho modificato il file di esempio togliendo le parti relative a “keyedtables” e “serialtables” e inserendo i nomi delle tabelle (con relativo schema) da replicare. Inoltre ho lasciato inalterate le impostazioni per “$CLUSTER_NAME = ‘replication’;” e “$LOGDIR = ‘/var/log/slony1’;”. La prima identificherà con un prefisso un nuovo schema nei due db e l’altra indica dove salvare i file di log.

Configurazione di slonik

Una volta editato il file di configurazione possiamo usalro per generare gli script da passare al modulo “slonik” (siamo sempre all’interno della  cirectory “/etc/slony/”).

# slonik_init_cluster > initcluster

# slonik_create set 1 > createset

# slonik_subscribe_set 1 2 > subscribeset

In questo modo vengono creati 3 file ognuno dei quali contiene il codice per impostare un cluster e farlo partire.

Accendere i motori

Ora possiamo fare partire il tutto:

# slonik < initcluster

che dovrebbe produrre un output simile a questo:

<stdin>:10: Set up replication nodes
<stdin>:13: Next: configure paths for each node/origin
<stdin>:16: Replication nodes prepared
<stdin>:17: Please start a slon replication daemon for each node

Può succedere che compaiano dei messaggi di errore (nel mio caso avevo scritto alcuni nomi di tabelle sbagliate nel file slon_tools.conf). In questo caso correggere il file suddetto, rimuovere i tre script creati con “# rm initcluster createset subscribset“, poi entrare dei due db “ctr_new” e “ctr_new_slave” e rimuovere lo schema “_replication” con “=# DROP SCHEDA -replication CASCADE;“. Infine ripartire con la creazione degli script di configurazione.

Avviamo slon sul server 1:

# slon_start 1

Invoke slon for node 1 – /usr/bin/slon -p /var/run/slony1/node1.pid -s 1000 -d2 replication ‘host=192.168.1.71 dbname=ctr_new user=postgres port=5432’ >>/var/log/slony1/node1-ctr_new.log 2>&1 </dev/null &
Slon successfully started for cluster replication, node node1
PID [5815]
Start the watchdog process as well…

e avviamo slon sul server 2:

# slon_start 2
Invoke slon for node 2 – /usr/bin/slon -p /var/run/slony1/node2.pid -s 1000 -d2 replication ‘host=100.0.4.71 dbname=ctr_new_slave user=postgres port=5432’ >>/var/log/slony1/node2-ctr_new_slave.log 2>&1 </dev/null &
Slon successfully started for cluster replication, node node2
PID [5879]
Start the watchdog process as well…

Ora creiamo cluster e subscribe

# slony < createset

<stdin>:16: Subscription set 1 created
<stdin>:17: Adding tables to the subscription set
<stdin>:21: Add primary keyed table public.aree_ter
<stdin>:25: Add primary keyed table public.astefer
<stdin>:29: Add primary keyed table public.asteflu
<stdin>:33: Add primary keyed table public.astevia
<stdin>:37: Add primary keyed table public.cam_fabb
<stdin>:41: Add primary keyed table public.curve
<stdin>:45: Add primary keyed table public.discont
<stdin>:49: Add primary keyed table public.ele_div
<stdin>:53: Add primary keyed table public.err_l
<stdin>:57: Add primary keyed table public.fabbr_l
<stdin>:61: Add primary keyed table public.fabbric
<stdin>:65: Add primary keyed table public.ferrovie
<stdin>:69: Add primary keyed table public.geometry_columns
<stdin>:73: Add primary keyed table public.idrogr_a
<stdin>:77: Add primary keyed table public.idrograf
<stdin>:81: Add primary keyed table public.infras_a
<stdin>:85: Add primary keyed table public.infrastr
<stdin>:89: Add primary keyed table public.inquadra
<stdin>:93: Add primary keyed table public.lim_amm
<stdin>:97: Add primary keyed table public.limamm_a
<stdin>:101: Add primary keyed table public.nodofer
<stdin>:105: Add primary keyed table public.nodoflu
<stdin>:109: Add primary keyed table public.nodovia
<stdin>:113: Add primary keyed table public.opere
<stdin>:117: Add primary keyed table public.punti_q
<stdin>:121: Add primary keyed table public.sim_disc
<stdin>:125: Add primary keyed table public.sim_elem
<stdin>:129: Add primary keyed table public.sim_fabb
<stdin>:133: Add primary keyed table public.sim_idro
<stdin>:137: Add primary keyed table public.sim_infr
<stdin>:141: Add primary keyed table public.sim_oper
<stdin>:145: Add primary keyed table public.sim_vege
<stdin>:149: Add primary keyed table public.sim_viab
<stdin>:153: Add primary keyed table public.spatial_ref_sys
<stdin>:157: Add primary keyed table public.testi
<stdin>:161: Add primary keyed table public.veget_a
<stdin>:165: Add primary keyed table public.vegetaz
<stdin>:169: Add primary keyed table public.viab_a
<stdin>:173: Add primary keyed table public.viabilit
<stdin>:176: Adding sequences to the subscription set
<stdin>:177: All tables added

Ed infine:

# slony < subscribeset

<stdin>:4: NOTICE:  subscribe set: omit_copy=f
<stdin>:4: NOTICE:  subscribe set: omit_copy=f
CONTEXT:  SQL statement “SELECT  “_replication”.subscribeSet_int( $1 ,  $2 ,  $3 ,  $4 ,  $5 )”
funzione PL/pgSQL “subscribeset” linea 68 a PERFORM
<stdin>:10: Subscribed nodes to set 1

Tutto è partito: se andiamo a vedere i file di log in “/var/log/slony/” vediamo cio’ che accade.

Per fare un test ho provato a caricare la stessa tabella (spaziale) in QGIS (la stessa tabella del db master e dello slave). Modificando (aggiunto un elemento geometrico) la tabella e facendo un refresh si notano quasi istantaneamenete i cambiamenti replicati anche nel db slave!

Ogni commento è benvenuto.


postgis | ST_Reverse()

0
0

Un piccolo e breve post su una funzione di Postgis molto utile per invertire l’ordine di digitalizzazione dei vertici di un oggetto. Nel caso specifico si fa riferimento ad oggetti lineari. La funzione è (brevemente) documentata qui. Ed ecco un esempio pratico per invertire il senso di 3 linee identificate mediante il loro gid:

#= UPDATE nome_tabella_linee SET the_geom = ST_Reverse(the_geom) WHERE gid IN (8,128,46);

I valori dei “gid” indicati sono puramente esemplificativi.


Postgis |unione di poligoni adiacenti

0
0

A partire da un layer multipolygon contenente edifici di una porzione di territorio (circa 1300 entità) avevo la necessità ci creare un nuovo layer (tabella) contenente i poligoni ottenuti dalla fusione di elementi adiacenti. La situazione di partenza è quella rappresentata in fig. 1.

buildingfig. 1

Utilizzando le funzioni di Postgis ho ottenuto il risultato mediante la seguente istruzione (viene creata una nuova tabella):

# CREATE TABLE nuova_tabella AS SELECT(ST_Dump(ST_Union(ST_Buffer(the_geom, 0.01)))).geom AS the_geom FROM tabella_origine;

Il risultato è quello di fig. 2

building_unionfig. 2

Se volessimo aggregare i poligoni anche in base al valore di un determinato attributo il comando diventa:

# CREATE TABLE nuova_tabella AS SELECT nome_campo, (ST_Dump(ST_Union(ST_Buffer(the_geom, 0.01)))).geom AS the_geom FROM tabella_origine GROUP BY nome_campo;


Da Postgresql-8.4 e Postgis-1.5 a Posgresql-9.5 e Postgis-2.2

0
0

Riporto le operazioni effettuate per migrare alcuni database da Postgresq-8.4 con estensione spaziale Postgis-1.5 a Postgresql-9.5 con Postgis-2.2.

Eseguire un dump dei dati con:

$ PGUSER=postgres pg_dump -Fc nome_db > nome_db.dmp

Questa operazione va fatta per ogni db presente nel cluster; si ottengono i relativi dump in formato compresso (.dmp) da utilizzare poi per l’importazione della nuova architettura.

Stoppare Postgresql-8.4 con (da root):

# /etc/init.d/postgresql stop 8.4

Installare la versione 9.5 di Postgresql e la versione 2.2 di Postgis (e dipendenze collegate) con:

# apt-get install postgresql-9.5 postgis postgis-2.2

A questo punto si potrebbe droppare il cluster della versione 8.4 con “pg_dropcluster –stop 8.4 main“. Nel mio caso ho invece preferito rimuovere Postgresql-8.4 e Postgis 1.5 con “apt-get purge postgresql-8.4*

Creare gli utenti dei db (nel nostro caso abbiamo ricreato gli utenti che avevamo prima di effettuare la migrazione):

$ su

# su postgres

Entrare in un db (es: template1):

# psql template1

e creare gli utenti necessari:

#= CREATE USER nome_utente WITH PASSWORD ‘password_segreta’ CREATEDB CREATEUSER;

(nel nostro caso l’utente creato avra’ la facolta’ di creare database e utenti)

Creare un template apposito per i db spaziali che chiameremo “template_gis”:

#= CREATE DATABASE template_gis template=template0;

Uscire dal database template1 e (sempre come utente postgres) importare le funzioni spaziali nel database appena creato:

# psql -d template_gis -f /usr/share/postgresql/9.5/contrib/postgis2.2/postgis.sql

# psql -d template_gis -f /usr/share/postgresql/9.5/contrib/postgis2.2/spatial_ref_sys.sql

# psql -d template_gis -f /usr/share/postgresql/9.5/contrib/postgis2.2/rtpostgis.sql

In questo modo abbiamo popolato il template_gis con tutti i sistemi di riferimento spaziali e tutte le funzioni dedicate alla manipolazione di dati vettoriali (“postgis.sql”  e raster “rtpostgis.sql”)

Ritornare all’interno del database template1:

# psql template1

e facciamo in mdo che il database template_gis sia un template:

#= UPDATE pg_database SET datistemplate=’t’ WHERE datname=’template_gis’;

Creare i database (uno alla volta)

#= CREATE DATABASE nome_db template=template_gis OWNER nome_utente;

Uscire dal template1 e popolare i nuovi database con l’aiuto dello script “postgis_restore.pl”:

$ /usr/share/postgresql/9.5/contrib/postgis-2.2/postgis_restore.sql nome_db.dmp | psql nome_db

 


Ocitysmap | Creare mappe con Vie indicizzate

0
0

Ho provato a replicare in locale l’ottimo servizio offerto da maposmatic.org (un’applicazione per generare porzioni di mappa stampabili come file PDF, PNG, SVG,…. comprendente l’elenco dei nomi delle vie indicizzate in una griglia).

Ho seguito le istruzioni di installazione riportate nel pacchetto ocitysmap alle quali pero’ ho dovuto apportare alcune modifiche (la guida fa riferimento ad una installazione eseguita su ubuntu 14.04, mentre io ho provato su Debian testing ad oggi – ottobre 2016).

Per comodità operativa (potrebbe non essere il metodo migliore) e per dare chiarezza di lettura ai passaggi da eseguire ho strutturato l’ambiente di lavoro in questo modo:

– posizionandosi nella home dell’utente ho creato una directory in cui salvare i sorgenti chiamata “src”

$ mkdir src

– sempre all’interno della home ho creato un’altra directory chiamata “osm_data” al cui interno salveremo i dati scaricati dal server OSM e che saranno importati successivamente nel db PostGIS

$ mkdir osm_data

 

Ed ecco il procedimento globale:

1 Installazione di PostgreSQL e PostGIS

# apt-get install postgresql postgresql-contrib postgresql-9.4-postgis-2.2 (PostgreSQL 9.4.5)

2 Creazione di un nuovo utente di PostgreSQL

diventare root:

$ su

diventare superuser postgres:

# su postgres

Creare il nuovo utente di PostgreSQL:

# createuser -P -S -D -R maposmatic

(chiamiamo “maposmatic” il nuovo utente; inserire la password due volte per conferma)

3 Creazione del database

# createdb -E UTF8 -O mapomsatic db_maposmatic

4 Abilitazione di PostGIS sul database

4.a Abilitare il linguaggio plpgsql sul database creato db_maposmatic (utente postgres)

# createlang plpgsql db_maposmatic

4.b Installazione del supporto PostGIS nel database

# psql -f /usr/share/postgresql/9.4/contrib/postgis-2.2/postgis.sql -d db_maposmatic

4.c Opzionalmente inseriamo anche i commenti

# psql -f /usr/share/postgresql/9.4/contrib/postgis-2.2/postgis_comments.sql -d db_maposmatic

4.d Aggiunta della lista dei sistemi di riferimento spaziale

# psql -f /usr/share/postgresql/9.4/contrib/postgis-2.2/spatial_ref_sys.sql -d db_maposmatic

4.e Cambiare il proprietario delle tabelle

# echo “ALTER TABLE geometry_columns OWNER TO maposmatic; ALTER TABLE spatial_ref_sys OWNER TO maposmatic;” | psql -d db_maposmatic

4.f Aggiungere l’estensione hstore

# echo “CREATE EXTENSION hstore;” | psql -d db_maposmatic

5 Installazione di osm2pgsql

osm2pgsql e’ lo strumento che consente di importare i dati OSM direttamente in un database PostGIS. La guida suggerisce di scaricare la versione da SVN in quanto quello pacchettizato Debian/Ubuntu non e’ abbastanza recente. Ho tentato comunque l’installazione via apt-get ed in realta’ tutto e’ andato bene, quindi:

# apt-get install osm2pgsql

6. Download dei dati dal server OSM

Il download dei dati si puo’ effettuare mediante il servizio offerto da geofabrik.de, per esempio cercando la zona di nostro interesse

In alternativa (nel caso volessimo un’area di dimensioni ridotte e/o comunque ben delimitate da una bounding box (bbox)) possiamo utilizzare il servzio offerto da overpass.osm.rambler.ru. In questo caso utilizziamo wget per scaricare una certa area geografica:

$ wget http://overpass.osm.rambler.ru/cgi/xapi_meta?*%5Bbbox=long_inf,lat_inf,long_sup,lat_sup%5D

tradotto con dati reali potrebbe essere:

$ wget http://overpass.osm.rambler.ru/cgi/xapi_meta?*%5Bbbox=11.3640,45.4650,11.4660,45.5780%5D

Si ottiene un file denominato “xapi_meta?*[bbox=11.4740,45.4150,11.5160,45.4650]” che potremo rinominare in “dati_osm.osm” (per esempio mediante il comando “mv”).

7 Importazione dei dati OSM all’interno del database PostGIS

L’importazione avviene mediante il seguente comando:

$ osm2pgsql -s -c -d db_maposmatic -m -U maposmatic -W -H localhost -k dati_osm.osm

A seconda della dimensione del file .osm il processo puo’ durare qualche secondo, minuto o ora (l’importazione di tutto il nord-est d’Italia, circa 750 MB, e’ durata circa 1 ora e mezza) e dipende molto dalle caratteristiche hardware del computer.

8 Installazione di Mapnik

8.a Installare python-mapnik

Via synaptic o apt-get o compilarlo da sorgente mediante “python setup.py install

8.b Installazione dipendenze

# apt-get build-dep python-mapnik

e installare altre librerie necessarie (in particolare e’ opportuno installare le librerie libboost piu’ recenti. Ad momento della stesura del presente articolo su Debian Testing si trovano le libboost-1.61):

# apt-get install libboost1.61-dev libboost-date-time1.61-dev libboost-filesystem1.61-dev libboost-iostreams1.61-dev libboost-program-options1.61-dev libboost-python1.61-dev libboost-regex1.61-dev libboost-serialization1.61-dev libboost-system1.61-dev libboost-thread1.61-dev libharfbuzz-dev

8.c Download Mapnik

Download dell’ultima versione di Mapnik dal repository git (dopo esseresi posizionati nella directory /home/nome_utente/src/):

$ cd src

Lanciare il download:

$ git clone git://github.com/mapnik/mapnik.git

Spostarsi nella directory creata durante il download “mapnik”:

$ cd mapnik

8.d Compilazione ed installazione

Prima di eseguire il config assicurarsi di fare un update dei submodule di mapnik:

$ git submodule update –init

$ git submodule update –init deps/mapbox/variant

Eseguire il config:

$ python scons/scons.py configure INPUT_PLUGINS=all OPTIMIZATION=3 SYSTEM_FONTS=/usr/share/fonts/ PYCAIRO=true XMLPARSER=libxml2

Compilare:

$ python scons/scons.py

Installare (dopo essersi loggati come root):

# python scons/scon.py install

8.e Controllo dell’installazione

Lanciare un interprete python ed invocare “import mapnik”:

$ python

dovremmo ottenere una cosa del tipo:

Python 2.7.12+ (default, Sep  1 2016, 20:27:38)
[GCC 6.2.0 20160927] on linux2
Type “help”, “copyright”, “credits” or “license” for more information.
>>>

quindi importiamo il modulo mapnik appena compilato:

>>> import mapnik
>>>

Se tutto e’ ok dovremmo ottenere il prompt in attesa di comandi; in tal caso significa che mapnik e’ stato compilato  ed installato correttamente.

9. Installazione di Mapnik-OSM

Mapnik-OSM e’ un set di file che indicano a Mapnik come renderizzare le mappe di OpenStreetMap.

9.a Download

Dopo essersi posizionati nella directory /home/nome_utente/src/ scarichiamo il sorgente mediante svn (nel caso svn non fosse presente installarlo via “apt-get install subversion”)

$ svn co http://svn.openstreetmap.org/applications/rendering/mapnik mapnik2-osm

Questo creera’ una nuova directory in /home/nome_utente/src chiamata “mapnik2-osm”

9.b Installazione dei dati statici generali

In aggiunta ai dati OSM sono necessari altri dati statici (world boundaries, ecc…)

$ cd mapnik2-osm

Invochiamo da shell il comando get-coastlines.sh che scarichera’ una serie di SHP delle linee di costa ed altri dati.

$ sh ./get-coastlines.sh

9.c Abilitazione degli unifont

Per un render corretto dei caratteri Coreano, Cinese o Giapponese si deve usare il font unifont. Per abilitarlo (da root):

# apt-get install ttf-unifont

E’ consigliato eseguire anche un reconfigure del locales:

# dpkg-reconfigure locales

9.d Configurazione

La configurazione avviene invocando lo script in python chiamato “generate_xml.py” che si trova in /home/nome_utente/src/mapnik2-osm/; spostarsi quindi nella directory interessata:

$ cd /home/sit/src/mapnik2-osm/

e lanciare il comando

$ python ./generate_xml.py –dbname db_maposmatic –host ‘localhost’ –user maposmatic –port 5432 –password ‘password_utente_maposmatic’

In risposta dovremmo ottenere un messaggio simile a questo:

Include files written successfully! Pass the osm.xml file as an argument if you want to serialize a new version or test reading the XML

10 Installazione di OCitySMap

10.a Recuperare i sorgenti

Posizionarsi sempre nella directory /home/sit/src/

$ git clone git://git.savannah.nongnu.org/maposmatic/ocitysmap.git

10.b Installazione delle dipendenze

# apt-get install python-psycopg2 python-gdal python-gtk2 python-cairo python-shapely

10.c Modifica di alcuni file di configurazione di OCitySMap

Editare il file /home/nome_utente/src/ocitysmap/ocitysmap/maplib/map_canvas.py alle righe 176 e 177. In particolare modificare la riga 176 nel modo seguente:

r.symbols.append(mapnik.PolygonSymbolizer())

e la riga 177 nel modo seguente:

r.symbols.append(mapnik.LineSymbolizer())

altrimenti durante il processo compariranno degli errori sull’impossibilita’ di eseguire alcuni render.

11 File di configurazione di OcitySMap

copiare il file /home/nome_utente/src/ocitysmap/ocitysmap.conf.dist nella home directory dell’utente e rinominarlo in “.ocitysmap.conf”. Da notare il punto davanti al nome del file: indica che il file e’ nascosto. Editarlo poi inserendo i dati corretti del database da utilizzare. Ecco il file .ocitysmap.conf usato in questa guida:

[datasource]
host=localhost
user=maposmatic
password=password
dbname=db_maposmatic
# Optional database port, defaults to 5432
# port=5432

[rendering]
# List of available stylesheets, each needs to be described by an eponymous
# configuration section in this file.
available_stylesheets: stylesheet_osm1, stylesheet_osm2

# The default Mapnik stylesheet.
[stylesheet_osm1]
name: Default
description: The default OSM style
path: /home/sit/src/mapnik2-osm/osm.xml

# Another stylesheet
[stylesheet_osm2]
name: AnotherOne
description: Another OSM Stylesheet
path: /home/sit/src/ocitysmap/stylesheet/maposmatic-printable/osm.xml

12 Lanciare OCitySMap

Spostarsi nella directory /home/nome_utente/src/ocitysmap/ e lanciare il comando per l’esecuzione del render:

$ ./render.py -t “titole della mappa” -f pdf -p nome_file_generato –osmid=-44831

nel caso si conoscesse l’osmid della relazione (in questo caso identifica un confine comunale) che intendiamo usare. Per ricavare l’osmid consultare l’ottimo servizio fornito da nominatim

lanciando il comando ./render.py –help si ottiene un elenco dettagliato dei comandi opzionali del modulo.

Se invece si volesse effettuare il render di una determinata area geografica e’ possibile indicarla con i valori del bbox, per esempio:

$ ./render.py -t “titolo della mappa” -f pdf -p nome_file_generato -b lat_inf,long_inf lat_sup,long_sup

dove lat_inf e long_inf sono rispettivamente la latitudine e la longitudine dell’estremo inferiore sinistro (o ovest) e lat_sup e long_sup sono rispettivamente la latitudine e longitudine dell’estremo superiore destro (o est). Tradotto don dati reali:

$ ./render.py -t “titolo della mappa” -f pdf -p nome_file_generato -b 45.3330,11.3280 45.4400,11.4595

Verranno generati due file: “nome_file_generato.pdf” contenente la mappa ed un file “nome_file_generato.csv” con l’elengo indicizzato della strade e dei luoghi di interesse trovati.

 


django | collegarsi al server web di lavoro (python) da client remoto

0
0

Quando si sviluppano applicazioni con django si ha a disposizione un server web “temporaneo” che si avvia con il comando:

$ python manage.py runserver

ed e’ raggiungibile all’indirizzo:

http://lcoalshot:8000

Se vogliamo accedervi da remoto bisogna lanciare prima il comando (sulla macchina client):

$ ssh -L 8888:127.0.0.1:8000 nome_utente@indirizzo_ip_server

per esempio:

$ ssh -L 8888:127.0.0.1:8000 sit@192.168.168.1

A questo punto possiamo collegarci mediante il browser puntando a:

http://localhost:8888

PS: E’ necessario avere avviato in precedenza il servizio con:

$ python manage.py runserver

sulla macchina host

Postgresql | Estrarre soltanto l’anno da un campo di tipo “date”

0
0

Come da titolo, per ottenere soltanto l’anno da un campo “date” (nella forma “aaaa-mm-gg”, per esempio: “2018-01-03”) eseguire la seguente istruzione:

nomedb=# SELECT date_part(‘year’, nome_colonna_date) FROM nome_tabella;


Postgresql | concatenare due tabelle che hanno la stessa struttura

0
0

Supponiamo di avere due tabelle (tabella01 e tabella02) e vogliamo concatenarle in una nuova tabella (in sostanza vogliamo accodare i record delle due tabelle). Ecco l’istruzione SQL (grazie a questo thread):

=# SELECT * INTO nuova_tabella FROM (SELECT * FROM tabella01 UNION SELECT * FROM tabella02) AS tmp;

Postgresql | aggiornare un campo con il solo valore ‘year’ di un altro campo di tipo DATE

0
0

Supponiamo di avere una tabella con un campo “data” di tipo DATE (nella forma “aaaa-mm-gg” – esempio: 2018-01-03) e vogliamo popolare un altro campo (per esempio “anno”) di tipo integer con il solo valore dell’anno prendendolo dal campo “data”. Ecco la sintassi SQL:

=# UPDATE nome_tabella SET anno=date_part(‘year’, data);

PostGIS | conversione da MULTISURFACE a POLYGON

0
0
Per convertire una tabella geometrica da MULTISURFACE a POLYGON è necessario prima creare una nuova tabella selezionando tutti i campi della tabella originaria con il comando: =# CREATE TABLE nome_tabella_new AS SELECT id, nome_campo1, come_campo2, ….ST_CurveToLine(the_geom) AS the geom FROM nome_tabella_originaria; nel nostro caso abbiamo ottenuto una tabella di tipo GEOMETRY, per cambiare in POLYGON…Read more PostGIS | conversione da MULTISURFACE a POLYGON

PostrgreSQL, PostGIS | disabilitare/abilitare Trigger

0
0

Se ad una tabella sono collegati dei trigger è possibile disabilitarli temporaneamente e riabilitarli in un secondo momento. Prima di tutto è necessario conoscere quali siano i trigger della tabella in oggetto con il comando:

=# \dS nome_tabella

che restituisce la lista dei trigger attivi.

Per disabilitarne uno:

=# ALTER TABLE nome_tabella DISABLE TRIGGER nome_trigger;

rilanciando il comando

=# \dS nome_tabella

vedremo che il trigger disabilitato verrà marcato con non attivo.

Per riabilitarlo:

=# ALTER TABLE nome_tabella ENABLE TRIGGER nome_trigger;

PostgreSQL-PostGIS | Database History – Cronologia delle modifiche utilizzando i trigger

0
0

Tratto, tradotto e leggermente modificato da: https://postgis.net/workshops/postgis-intro/history_tracking.html


Questo articolo non è assolutamente “farina del mio sacco”; ho soltanto tradotto e leggermente modificato quanto riportato in una pagina fatta molto bene (ringrazio sentitamente l’autore o gli autori) che si trova qui: https://postgis.net/workshops/postgis-intro/history_tracking.html adattando l’esempio ai dati che ho utilizzato per fare un test. Funziona davvero bene!


Un requisito comune per i database è la capacità di tenere traccia della cronologia: come sono cambiati i dati tra due date, chi ha apportato le modifiche e dove si sono verificate?

Utilizzando il database e il sistema di trigger, è possibile aggiungere il monitoraggio della cronologia a qualsiasi tabella, mantenendo un semplice accesso di “modifica diretta” alla tabella principale.

Il monitoraggio della cronologia funziona mantenendo una tabella della cronologia che registra, per ogni modifica:

  • Se un record è stato creato, quando è stato aggiunto e da chi.
  • Se un record è stato eliminato, quando è stato eliminato e da chi.
  • Se un record è stato aggiornato, aggiungendo un record di cancellazione (per il vecchio stato) e un record di creazione (per il nuovo stato).

Utilizzo di TSTZRANGE

La tabella della cronologia utilizza una funzionalità specifica di PostgreSQL, il tipo “intervallo di timestamp” (tstzrange), per memorizzare l’intervallo di tempo in cui un record della cronologia era il record “live”. Tutti gli intervalli di timestamp nella tabella della cronologia per una particolare caratteristica non si sovrappongono ma restano adiacenti.

L’intervallo per un nuovo record inizierà a now() e avrà un punto finale aperto, in modo che l’intervallo copra tutto il tempo dall’ora corrente al futuro.

Impartendo il comando seguente:

=# SELECT tstzrange(current_timestamp, NULL);

Otterremo per esempio:

=#

tstzrange
————————————
[“2023-08-01 14:49:40.910074-07”,)

Allo stesso modo, l’intervallo di tempo per un record eliminato verrà aggiornato per includere l’ora corrente come punto finale dell’intervallo di tempo.

La ricerca di intervalli di tempo è molto più semplice della ricerca di una coppia di timestamp: un intervallo di tempo aperto comprende tutto il tempo dal punto iniziale all’infinito. Per gli intervalli useremo l’operatore “contiene” @>. Per esempio:

=# SELECT tstzrange(current_timestamp – ’10m’::interval, NULL) @> current_timestamp;

Gli intervalli possono essere indicizzati in modo molto efficiente utilizzando un indice GIST, proprio come i dati spaziali, come mostreremo di seguito. Ciò rende le query di cronologia molto efficienti.

Costruire la tabella della storia (history)

Utilizzando queste informazioni è possibile ricostruire lo stato della tabella di modifica in qualsiasi momento. Partiamo per esempio da una tabella che contiene lo stradario (strade); aggiungeremo quindi il monitoraggio della cronologia alla nostra tabella “strade”.

Innanzitutto, aggiungiamo una nuova tabella “strade_history”. Questa è la tabella che useremo per memorizzare tutte le informazioni di modifica storiche. Oltre a tutti i campi di “strade”, aggiungiamo altri quattro campi.

  • hid: la chiave primaria per la tabella della cronologia
  • created_by: l’utente del database che ha creato il record
  • deleted_by: l’utente del database che ha causato la marcatura del record come cancellato
  • valid_range: l’intervallo di tempo entro il quale il record era “live”

Si noti che in realtà non eliminiamo alcun record nella tabella della cronologia, contrassegniamo solo l’ora in cui hanno cessato di far parte dello stato corrente della tabella di modifica.

=# CREATE TABLE strade_history (hid SERIAL PRIMARY KEY, gid INTEGER, nome VARCHAR(50), geom GEOMETRY (MULTILINESTRING, 3003), valid_range TSTZRANGE, created_by VARCHAR(32), deleted_by VARCHAR(32));

=# CREATE INDEX strade_history_geom_x ON strade_history USING GIST (geom);

=# CREATE INDEX strade_history_tstz_x ON strade_history USING GIST (valid_range);

Successivamente, importiamo lo stato corrente della tabella attiva, “strade” nella tabella della cronologia, in modo da avere un punto di partenza da cui tracciare la cronologia. Si noti che inseriamo l’ora di creazione e l’utente di creazione, ma lasciamo NULL la fine dell’intervallo di tempo e l’informazione “deleted_by”.

=# INSERT INTO strade_history (gid, nome, geom, valid_range, created_by) SELECT gid, nome, geom, tstzrange(now(), NULL), current_user FROM strade;

Ora abbiamo bisogno di tre trigger sulla tabella attiva, per le azioni INSERT, DELETE e UPDATE. Per prima cosa creiamo le funzioni trigger, quindi le colleghiamo alla tabella come trigger.

Per un nuovo inserimento, aggiungiamo semplicemente un nuovo record nella tabella della cronologia con l’ora di creazione/utente.

=# CREATE OR REPLACE FUNCTION strade_insert() RETURNS trigger AS
$$
BEGIN
INSERT INTO strade_history
(gid, nome, geom, valid_range, created_by)
VALUES
(NEW.gid, NEW.nome, NEW.geom,
tstzrange(current_timestamp, NULL), current_user);
RETURN NEW;
END;
$$
LANGUAGE plpgsql;

Quindi creiamo il primo trigger per l’inserimento

=# CREATE TRIGGER strade_insert_trigger AFTER INSERT ON strade FOR EACH ROW EXECUTE PROCEDURE strade_insert();

Per la cancellazione, contrassegniamo semplicemente il record della cronologia attualmente attivo (quello con un tempo di cancellazione NULL) come cancellato.

=# CREATE OR REPLACE FUNCTION strade_delete() RETURNS trigger AS
$$
BEGIN
UPDATE strade_history
SET valid_range = tstzrange(lower(valid_range), current_timestamp),
deleted_by = current_user
WHERE valid_range @> current_timestamp AND gid = OLD.gid;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;

E relativo trigger per l’eliminazione:

=# CREATE TRIGGER strade_delete_trigger AFTER DELETE ON strade FOR EACH ROW EXECUTE PROCEDURE strade_delete();

Per un aggiornamento, prima contrassegniamo il record della cronologia attivo come eliminato, quindi inseriamo un nuovo record per lo stato aggiornato.

=# CREATE OR REPLACE FUNCTION strade_update() RETURNS trigger AS
$$
BEGIN
UPDATE strade_history
SET valid_range = tstzrange(lower(valid_range), current_timestamp),
deleted_by = current_user
WHERE valid_range @> current_timestamp AND gid = OLD.gid;
INSERT INTO strade_history
(gid, nome, geom, valid_range, created_by)
VALUES
(NEW.gid, NEW.nome, NEW.geom,
tstzrange(current_timestamp, NULL), current_user);
RETURN NEW;
END;
$$
LANGUAGE plpgsql;

E relativo trigger per l’aggiornamento:

=# CREATE TRIGGER strade_update_trigger AFTER UPDATE ON strade FOR EACH ROW EXECUTE PROCEDURE strade_update();

Modificare la tabella

Ora che la tabella della cronologia è abilitata, possiamo apportare modifiche alla tabella principale (“strade”) e guardare le voci del registro apparire nella tabella della cronologia (“history_strade”).

Da notare la potenza di questo approccio alla cronologia basato su database: indipendentemente dallo strumento utilizzato per apportare le modifiche, che si tratti della riga di comando SQL, di uno strumento JDBC basato sul Web o di uno strumento desktop come QGIS, la cronologia viene costantemente monitorata.

Modifiche SQL

Trasformiamo la due strada denominata “VIA ROMA” in “VIA ROMA IMPERIALE” (per esempio):

L’aggiornamento della strada farà sì che la strada originale venga contrassegnata come cancellata nella tabella della cronologia, con un’ora di eliminazione di adesso, e una nuova strada con l’aggiunta del nuovo nome, con un’ora di aggiunta di adesso. Possiamo consultare i dati storici.

Interrogazione della tabella cronologica

Ora che abbiamo una tabella cronologica, a cosa serve? È utile per viaggiare nel tempo! Per viaggiare in un particolare tempo T, è necessario costruire una query che includa:

  • Tutti i record creati prima di T e non ancora cancellati; e anche
  • Tutti i record creati prima di T, ma eliminati dopo T.

Possiamo usare questa logica per creare una query, o una vista, dello stato dei dati nel passato. Poiché presumibilmente tutte le tue modifiche di prova sono avvenute negli ultimi due minuti, creiamo una vista della tabella della cronologia che mostri lo stato della tabella 10 minuti fa, prima che si iniziasse a modificare (quindi, i dati originali).

=# CREATE OR REPLACE VIEW strade_dieci_min_ago AS SELECT * FROM strade_history WHERE valid_range @> (now() – ’10min’::interval);

Caricando questa vista su QGIS possiamo vedere i dati come erano 10 minuti fa

Se invece volessimo recuperare la versione della tabella ad una certa data (per esempio alla data del 01 agosto 2023):

=# CREATE OR REPLACE VIEW strade_al_20230801 AS SELECT strade_history.hid, strade_history.gid, strade_history.nome, strade_history.geom, strade_history.valid_range, strade_history.created_by, strade_history.deleted_by FROM strade_history WHERE lower(strade_history.valid_range) < ‘2023-08-02 13:10:38’;

In questo modo avremo tutti gli oggetti presenti nel database prima del 2 agosto 2023 alle ore 13:10:38″. Verranno pertanto esclusi tutti gli oggetti creati, modificati o eliminati dopo quel momento.

Viewing all 20 articles
Browse latest View live




Latest Images

Vimeo 10.7.0 by Vimeo.com, Inc.

Vimeo 10.7.0 by Vimeo.com, Inc.

HANGAD

HANGAD

MAKAKAALAM

MAKAKAALAM

Doodle Jump 3.11.30 by Lima Sky LLC

Doodle Jump 3.11.30 by Lima Sky LLC

Doodle Jump 3.11.30 by Lima Sky LLC

Doodle Jump 3.11.30 by Lima Sky LLC

Vimeo 10.6.1 by Vimeo.com, Inc.

Vimeo 10.6.1 by Vimeo.com, Inc.

Vimeo 10.6.0 by Vimeo.com, Inc.

Vimeo 10.6.0 by Vimeo.com, Inc.

Re:

Re:

Re:

Re: