Bagaimana cara membuat skrip pemrosesan QGIS yang menambahkan urutan ke kolom pengidentifikasi unik di PostGIS?

10

Adakah yang bisa membantu saya membuat skrip pemrosesan QGIS yang menambahkan urutan ke kolom pengidentifikasi unik yang ada (ketik: integer) di PostGIS?

Ini akan sangat membantu, misalnya sebagai solusi untuk bug # 6798 . Sayangnya, saya tidak punya pengalaman Python.

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

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);
eclipsed_by_the_moon
sumber
1
Saya akan bertanya mengapa dalam alur kerja Anda, dan alur kerja yang dijelaskan dalam bug, Anda tidak mengelola data PostgreSQL Anda menggunakan PGAdmin atau alat admin inti lainnya untuk postgresql? Saya tidak tahu mengapa ada upaya yang dihabiskan untuk membuat ini berfungsi di QGIS ketika alat admin melakukannya dengan baik!
DPSSpatial
Bagi saya, mengelola tabel di QGIS DB-Manager cukup intuitif. Namun, saya juga tertarik untuk melihat bagaimana skrip pemrosesan dapat menjalankan kueri PostGIS.
eclipsed_by_the_moon
3
Bagi kami, PGAdmin dan jendela SQL lebih merupakan "GIS" kami daripada QGIS! QGIS hanyalah klien visual untuk data dan output spasial kami - semua pekerjaan, termasuk pemrosesan 'geo', skrip, dll. Dilakukan di luar QGIS ... alat yang ada untuk melakukan ini sudah disempurnakan, dan sungguh, alur kerja menggunakan alat non-QGIS ini dengan data PostgresSQL / PostGIS adalah praktik yang lebih baik ...
DPSSpatial

Jawaban:

2

Perlu dicatat, bahwa modul python psycopg2sepertinya tidak secara otomatis COMMITmelakukan transaksi (seperti yang dilakukan klien lain seperti QGIS DB Manager atau pgAdmin), oleh karena itu COMMITpernyataan tersebut harus menjadi bagian dari sqlstring dalam skrip.

Ini tidak masalah dengan SELECTpernyataan karena dalam kasus COMMITini jelas dilakukan ketika mendapatkan hasil melalui cur.fetchall().

Ini adalah versi ulang skrip dari jawaban saya di atas:

#!/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
sumber
6

Asalkan pernyataan SQL Anda menghasilkan hasil yang valid, skrip di bawah ini harus melakukan apa yang Anda cari. Sayangnya saya tidak punya apa-apa untuk menguji ini, tetapi Anda bisa mencoba dan memberikan umpan balik.

Saya mencoba berkomentar untuk kenyamanan, pada dasarnya skrip melakukan tiga langkah:

  • memperoleh parameter koneksi basis data untuk lapisan yang dipilih (harus postgres)
  • isi parameter koneksi dalam string pernyataan sql
  • jalankan pernyataan sql

Perhatikan output protokol skrip.

#!/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
sumber
Saya telah menguji skrip dan kata pemrosesan log unexpected indent (, line 32) See log for more details. Apakah ada yang salah yang saya lakukan? Pernyataan SQL bekerja di 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
Yap, salahku. The trypernyataan memiliki lekukan yang salah. Baru saja perbaiki ini.
Jochen Schwarze
Terima kasih untuk memperbaiki ini, tapi saya mendapatkan kesalahan Python ketika menjalankan skrip.
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

Tampaknya sudah ada plugin serupa (meskipun itu menciptakan bidang ID unik baru untuk Anda, daripada membuat urutan.)

Ini mengasumsikan Anda sudah memiliki bidang id unik (ini tidak harus berupa angka), tetapi sebaliknya menginginkan nomor numerik yang sederhana (1,2,3 ..)

Di Memproses kotak alat, buka Skrip> Alat> Dapatkan Skrip dari Online ...

Luaskan "Tidak diinstal" dan pilih "EquivalentNumField". Ingatlah untuk mengklik kotak centang sebelum mengklik OK. Itu membuat saya keluar ... ;-)

masukkan deskripsi gambar di sini

Untuk menemukannya dengan cepat, ketikkan "Equiv" di bilah pencarian pemrosesan, dan Anda harus dapat mengklik dua kali dari sana.

masukkan deskripsi gambar di sini

Ini sebuah contoh. Kayu-kayu ini memiliki bidang unik (osm_id) tetapi plugin telah menambahkan NUM_FIELD dengan nilai numerik sederhana sebagai gantinya

masukkan deskripsi gambar di sini

Steven Kay
sumber
Steve, ini skrip yang berguna, tetapi saya mencari sesuatu yang berbeda.
eclipsed_by_the_moon
@eclipsed_by_the_moon bagaimana jawaban ini bukan yang Anda cari? Tampaknya untuk akhirnya menyelesaikan masalah Anda membutuhkan kolom pengidentifikasi unik.
kttii