PostGISの一意の識別子列にシーケンスを追加するQGIS処理スクリプトを作成するにはどうすればよいですか?


10

PostGISの既存の一意の識別子列(タイプ:整数)にシーケンスを追加するQGIS処理スクリプトの作成を手伝ってくれる人はいますか?

これは、たとえばバグ#6798の回避策として非常に役立ちます。残念ながら、私はPythonの経験がありません。

ここに画像の説明を入力してください

ここに画像の説明を入力してください

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);

1
なぜワークフローで、そしてバグで説明されているワークフローで、PGAdminまたはpostgresql用の他のコア管理ツールを使用してPostgreSQLデータを管理していないのですか?管理ツールがうまく機能するのに、なぜQGISでこれを機能させるのに労力が費やされたのかわかりません!
DPSSpatial 2016

私にとって、QGIS DB-Managerでのテーブルの管理は非常に直感的です。ただし、処理スクリプトでPostGISクエリを実行する方法にも興味があります。
eclipsed_by_the_moon 2016

3
私たちにとって、PGAdminとSQLウィンドウは、QGISよりも「GIS」の詳細です。QGISは空間データと出力の視覚的なクライアントにすぎません。「ジオ」処理、スクリプトなどを含むすべての作業はQGISの外部で行われます...これを行うために存在するツールはすでに完成されており、本当に、 PostgresSQL / PostGISデータでこれらの非QGISツールを使用するワークフローはより良い実践です...
DPSSpatial

回答:


2

(QGIS DB ManagerやpgAdminのような他のクライアントのように)pythonモジュールpsycopg2は自動的COMMITにトランザクションのようには見えないため、COMMITステートメントはsqlスクリプト内の文字列の一部である必要があります。

SELECTこれらのケースでCOMMITはa は明らかにを介して結果を取得するときに実行されるため、これはステートメントには関係ありませんcur.fetchall()

これは、上記の私の回答からのスクリプトの書き直したバージョンです。

#!/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.')

6

SQLステートメントが有効な結果を生成する場合、以下のスクリプトはあなたが望んでいることを実行するはずです。残念ながら、私にはこれをテストする手がありませんが、フィードバックを試みて与えることができます。

私は便宜上コメントを付けましたが、基本的にスクリプトは3つのステップを実行します。

  • 選択したレイヤーのデータベース接続パラメーターを取得します(postgresである必要があります)
  • SQLステートメント文字列に接続パラメータを入力します
  • SQLステートメントを実行する

スクリプトのプロトコル出力に注意してください。

#!/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.')

私はスクリプトをテストしました、そして処理ログは言いunexpected indent (, line 32) See log for more detailsます。私が間違っていることはありますか?SQLステートメントはDB-Managerで機能しています。
eclipsed_by_the_moon 2016

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 2016

うん、私のせい。try文は間違ったインデントを持っていました。これを修正しました。
Jochen Schwarze

これを修正するためのThxですが、スクリプトの実行時にPythonエラーが発生します。
eclipsed_by_the_moon 2016

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 2016

3

すでに同様のプラグインがあるようです(ただし、シーケンスを作成するのではなく、新しい一意のIDフィールドを作成します)。

これは、一意のIDフィールドすでにあることを前提としていますが(これは数値である必要はありません)、代わりに単純な数値IDが必要です(1,2,3 ..)。

処理ツールボックスで、[スクリプト]> [ツール]> [オンラインからスクリプトを取得...]に移動します。

「インストールされていません」を展開し、「EquivalentNumField」を選択します。[OK]をクリックする前に、必ずチェックボックスをクリックしてください。それは私を見つけました... ;-)

ここに画像の説明を入力してください

それをすばやく見つけるには、処理中の検索バーに「Equiv」と入力すると、そこからダブルクリックできるはずです。

ここに画像の説明を入力してください

ここに例があります。これらの森には一意のフィールド(osm_id)がありましたが、プラグインは代わりに単純な数値のNUM_FIELDを追加しました

ここに画像の説明を入力してください


スティーブ、これは便利なスクリプトですが、何か違うものを探しています。
eclipsed_by_the_moon

@eclipsed_by_the_moonこの答えはあなたが探しているものではありませんか?一意の識別子列が必要になるという問題を最終的に解決するようです。
kttii 16
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.