Wie erstelle ich ein QGIS-Verarbeitungsskript, das einer eindeutigen Bezeichnerspalte in PostGIS eine Sequenz hinzufügt?

10

Kann mir jemand helfen, ein QGIS-Verarbeitungsskript zu erstellen, das einer vorhandenen eindeutigen Bezeichnerspalte (Typ: Ganzzahl) in PostGIS eine Sequenz hinzufügt?

Dies wäre sehr hilfreich, z. B. als Problemumgehung für Fehler Nr. 6798 . Leider habe ich keine Python-Erfahrung.

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

CREATE SEQUENCE /*input_schema*/./*input_table*/_/*uic*/_seq OWNED BY /*input_schema*/./*input_table*/./*uic*/;
SELECT SETVAL('/*input_schema*/./*input_table*/_/*uic*/_seq', (SELECT MAX(/*uic*/) FROM /*input_schema*/./*input_table*/));
ALTER TABLE /*input_schema*/./*input_table*/
ALTER COLUMN /*uic*/ SET DEFAULT nextval('/*input_schema*/./*input_table*/_/*uic*/_seq'::regclass);
verdunkelt durch den Mond
quelle
1
Ich würde fragen, warum Sie in Ihrem Workflow und dem im Fehler beschriebenen Workflow Ihre PostgreSQL-Daten nicht mit PGAdmin oder anderen zentralen Admin-Tools für Postgresql verwalten. Ich weiß nicht, warum es Mühe gibt, diese Arbeit in QGIS zu machen, wenn die Admin-Tools es gut machen!
DPSSpatial
Das Verwalten von Tabellen im QGIS DB-Manager ist für mich sehr intuitiv. Ich bin jedoch auch interessiert zu sehen, wie ein Verarbeitungsskript PostGIS-Abfragen ausführen kann.
Eclipsed_by_the_moon
3
Für uns sind PGAdmin und das SQL-Fenster mehr unser "GIS" als QGIS! QGIS ist nur der visuelle Client für unsere räumlichen Daten und Ausgaben - alle Arbeiten, einschließlich Geoverarbeitung, Skripte usw., werden außerhalb von QGIS ausgeführt. Die dafür vorhandenen Tools sind bereits perfektioniert und wirklich. Der Workflow der Verwendung dieser Nicht-QGIS-Tools mit PostgresSQL / PostGIS-Daten ist eine bessere Vorgehensweise ...
DPSSpatial

Antworten:

2

Es ist erwähnenswert, dass das Python-Modul psycopg2nicht automatisch COMMITeine Transaktion zu sein scheint (wie es andere Clients wie QGIS DB Manager oder pgAdmin tun), daher muss die COMMITAnweisung Teil der sqlZeichenfolge im Skript sein.

Dies spielt bei SELECTAussagen keine Rolle , da in diesen Fällen a COMMIToffensichtlich ausgeführt wird, wenn Ergebnisse über erhalten werden cur.fetchall().

Dies ist eine überarbeitete Version des Skripts aus meiner obigen Antwort:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#--------- define Interface
##[my_scripts]=group
##Add Serial to PostgreSQL Table=name
##Postgres_Table=vector
##Unique_identifier_column=field Postgres_Table

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import *

from qgis.core import *
from qgis.gui import *
from qgis.utils import *

import psycopg2

#get the parameters for the tpg table into a directory
#get the table
pg_table = processing.getObject(Postgres_Table)
#create empty dictionary for key/value pairs of the tables connection parameters
db_params = {}
db_params['uic'] = Unique_identifier_column
#iterate over connection string
progress.setInfo(20*'-' + '  Connection parameters')
for param in pg_table.dataProvider().dataSourceUri().split(' '):
    key_val = param.split('=')
    progress.setInfo(str(key_val))
    try:
        #set key/value pair
        db_params[key_val[0]] = key_val[1]
    except:
        pass

#generate the sql statement string
#the text in round brackets are the keys from the db_params dictionary created above
#the values belonging to the keys are inserted into the string
progress.setInfo(20*'-' + '  SQL statement')
sql = """CREATE SEQUENCE %(table)s_%(uic)s_seq OWNED BY %(table)s.%(uic)s;
SELECT SETVAL('%(table)s_%(uic)s_seq', (SELECT MAX(%(uic)s) FROM %(table)s)); 
ALTER TABLE %(table)s ALTER COLUMN %(uic)s SET DEFAULT nextval('%(table)s_%(uic)s_seq'::regclass);
COMMIT;""" % db_params
#remove double quotes
sql = sql.replace('"','') 
progress.setInfo(sql)

#make connection string
constr = """dbname=%(dbname)s host=%(host)s port=%(port)s user=%(user)s     password=%(password)s""" % db_params
progress.setInfo(20*'-' + '  DB Connection string')
progress.setInfo(constr)
#make db connection
con = psycopg2.connect(constr)
cur = con.cursor()
#execute the above created sql statement
progress.setInfo(20*'-' + '  Executing SQL statement ...')
cur.execute(sql)
progress.setInfo(20*'-' + '  ... done.')
Jochen Schwarze
quelle
6

Vorausgesetzt, Ihre SQL-Anweisung liefert gültige Ergebnisse, sollten die folgenden Skripte das tun, wonach Sie suchen. Leider habe ich nichts zur Hand, um dies zu testen, aber Sie könnten versuchen, Feedback zu geben.

Ich habe versucht, es der Einfachheit halber zu kommentieren. Im Grunde führt das Skript drei Schritte aus:

  • Datenbankverbindungsparameter für die ausgewählte Ebene erhalten (sollte postgres sein)
  • Füllen Sie die Verbindungsparameter in die SQL-Anweisungszeichenfolge ein
  • Führen Sie die SQL-Anweisung aus

Beachten Sie die Protokollausgabe des Skripts.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#--------- define Interface
##[my_scripts]=group
##Add Serial to PostgreSQL Table=name
##Postgres_Table=vector
##Unique_identifier_column=string replace_this_with_your_uic

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import *

from qgis.core import *
from qgis.gui import *
from qgis.utils import *

import psycopg2

#get the parameters for the tpg table into a directory
#get the table
pg_table = processing.getObject(Postgres_Table)
#create empty dictionary for key/value pairs of the tables connection parameters
db_params = {}
db_params['uic'] = Unique_identifier_column
#iterate over connection string
progress.setInfo(20*'-' + '  Connection parameters')
for param in pg_table.dataProvider().dataSourceUri().split(' '):
    key_val = param.split('=')
    progress.setInfo(str(key_val))
    try:
        #set key/value pair
        db_params[key_val[0]] = key_val[1]
    except:
        pass

#generate the sql statement string
#the text in round brackets are the keys from the db_params dictionary created above
#the values belonging to the keys are inserted into the string
progress.setInfo(20*'-' + '  SQL statement')
sql = """CREATE SEQUENCE %(table)s_%(uic)s_seq OWNED BY %(table)s.%(uic)s;
            SELECT SETVAL(%(table)s_%(uic)s_seq, (SELECT MAX(%(uic)s) FROM %(table)s));
            ALTER TABLE %(table)s
            ALTER COLUMN %(uic)s SET DEFAULT nextval(%(table)s_%(uic)s_seq::regclass);""" % db_params
#remove double quotes
sql = sql.replace('"','') 
progress.setInfo(sql)

#make connection string
constr = """dbname=%(dbname)s host=%(host)s port=%(port)s user=%(user)s     password=%(password)s""" % db_params
progress.setInfo(20*'-' + '  DB Connection string')
progress.setInfo(constr)
#make db connection
con = psycopg2.connect(constr)
cur = con.cursor()
#execute the above created sql statement
progress.setInfo(20*'-' + '  Executing SQL statement ...')
cur.execute(sql)
progress.setInfo(20*'-' + '  ... done.')
Jochen Schwarze
quelle
Ich habe das Skript getestet und das Verarbeitungsprotokoll sagt unexpected indent (, line 32) See log for more details. Gibt es etwas, was ich falsch mache? Die SQL-Anweisung funktioniert im DB-Manager.
eclipsed_by_the_moon
File "C:/Users/abc/.qgis2/python/plugins\processing\core\GeoAlgorithm.py", line 230, in execute self.processAlgorithm(progress) File "C:/Users/abc/.qgis2/python/plugins\processing\script\ScriptAlgorithm.py", line 298, in processAlgorithm exec((script), ns) File "<string>", line 32 try: ^
Eclipsed_by_the_moon
Ja, meine Schuld. Die tryAussage hatte einen falschen Einzug. Habe das gerade behoben.
Jochen Schwarze
Danke, dass du das behoben hast, aber beim Ausführen des Skripts wird ein Python-Fehler angezeigt.
Eclipsed_by_the_moon
Traceback (most recent call last): File "C:/Users/abc/.qgis2/python/plugins\processing\gui\AlgorithmDialog.py", line 219, in accept if runalg(self.alg, self): File "C:/Users/abc/.qgis2/python/plugins\processing\gui\AlgorithmExecutor.py", line 51, in runalg alg.execute(progress) File "C:/Users/abc/.qgis2/python/plugins\processing\core\GeoAlgorithm.py", line 244, in execute unicode(e) + self.tr('\nSee log for more details')) UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 44: ordinal not in range(128)
Eclipsed_by_the_moon
3

Es scheint bereits ein ähnliches Plugin zu geben (obwohl es ein neues eindeutiges ID-Feld für Sie erstellt, anstatt eine Sequenz zu erstellen.)

Dies setzt voraus, dass Sie bereits ein eindeutiges ID-Feld haben (dieses muss nicht numerisch sein), sondern stattdessen eine einfache numerische ID (1,2,3 ..) möchten.

Gehen Sie in der Toolbox "Verarbeitung" zu " Skripte"> "Extras"> "Skripte aus dem Internet abrufen".

Erweitern Sie "Nicht installiert" und wählen Sie "EquivalentNumField". Denken Sie daran, das Kontrollkästchen zu aktivieren, bevor Sie auf OK klicken. Das hat mich erwischt ... ;-)

Geben Sie hier die Bildbeschreibung ein

Um es schnell zu finden, geben Sie "Equiv" in die Verarbeitungssuchleiste ein, und Sie sollten in der Lage sein, von dort aus darauf zu doppelklicken.

Geben Sie hier die Bildbeschreibung ein

Hier ist ein Beispiel. Diese Hölzer hatten ein eindeutiges Feld (osm_id), aber das Plugin hat stattdessen ein NUM_FIELD mit einfachen numerischen Werten hinzugefügt

Geben Sie hier die Bildbeschreibung ein

Steven Kay
quelle
Steve, das ist ein nützliches Skript, aber ich suche etwas anderes.
Eclipsed_by_the_moon
@eclipsed_by_the_moon wie ist diese Antwort nicht das, wonach Sie suchen? Es scheint letztendlich Ihr Problem zu lösen, eine eindeutige Bezeichnungsspalte zu benötigen.
kttii