Как создать сценарий обработки QGIS, который добавляет последовательность к столбцу уникального идентификатора в PostGIS?

10

Кто-нибудь может мне помочь создать сценарий обработки QGIS, который добавляет последовательность к существующему столбцу уникального идентификатора (тип: целое число) в PostGIS?

Это было бы весьма полезно, например, в качестве обходного пути для ошибки № 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);
eclipsed_by_the_moon
источник
1
Я хотел бы спросить, почему в вашем рабочем процессе и рабочем процессе, описанном в сообщении об ошибке, вы не управляете своими данными PostgreSQL с помощью PGAdmin или других основных инструментов администратора для postgresql? Я не знаю, почему усилия затрачиваются на выполнение этой работы в QGIS, когда инструменты администратора делают это отлично!
DPSSpatial
Для меня управление таблицами в QGIS DB-Manager довольно интуитивно понятно. Однако мне также интересно посмотреть, как сценарий обработки может выполнять запросы PostGIS.
eclipsed_by_the_moon
3
Для нас PGAdmin и окно SQL - это больше наша «ГИС», чем QGIS! QGIS - это просто визуальный клиент для наших пространственных данных и выходных данных - вся работа, включая гео-обработку, скрипты и т. Д., Выполняется за пределами QGIS ... инструменты, которые существуют для этого, уже усовершенствованы и действительно рабочий процесс использования этих инструментов, не относящихся к QGIS, с данными PostgresSQL / PostGIS - лучшая практика ...
DPSSpatial

Ответы:

2

Стоит отметить, что модуль python psycopg2не кажется автоматически COMMITтранзакцией (как это делают другие клиенты, такие как QGIS DB Manager или pgAdmin), поэтому COMMITоператор должен быть частью sqlстроки в скрипте.

Это не имеет значения для SELECTутверждений, потому что в этих случаях a COMMIT, очевидно, выполняется при получении результатов через 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 дает правильные результаты, приведенные ниже сценарии должны делать то, что вам нужно. К сожалению, у меня нет ничего под рукой, чтобы проверить это, но вы можете попробовать и дать отзыв.

Я попытался прокомментировать это для удобства, в основном скрипт выполняет три шага:

  • получить параметры подключения к базе данных для выбранного слоя (должен быть 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
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
Да, я виноват. tryЗаявление было неправильно отступов. Просто исправил это.
Йохен Шварц
Спасибо за исправление, но я получаю ошибку Python при запуске скрипта.
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

Похоже, что подобный плагин уже есть (хотя он создает для вас новое уникальное поле идентификатора, а не последовательность).

Предполагается, что у вас уже есть уникальное поле идентификатора (оно не обязательно должно быть числовым), но вместо этого вам нужен простой числовой идентификатор (1,2,3 ..)

В панели инструментов Обработка перейдите в Сценарии> Инструменты> Получить сценарии из Интернета ...

Разверните «Не установлено» и выберите «EquivalentNumField». Не забудьте установить флажок перед нажатием кнопки ОК. Это застало меня врасплох ... ;-)

введите описание изображения здесь

Чтобы быстро найти его, введите «Эквив» в строке поиска обработки, и вы сможете дважды щелкнуть по нему.

введите описание изображения здесь

Вот пример. Эти леса имели уникальное поле (osm_id), но плагин добавил NUM_FIELD с простыми числовыми значениями

введите описание изображения здесь

Стивен Кей
источник
Стив, это полезный сценарий, но я ищу что-то другое.
eclipsed_by_the_moon
@eclipsed_by_the_moon как этот ответ не то, что вы ищете? Похоже, что в конечном итоге решить вашу проблему с необходимостью столбца уникальный идентификатор.
kttii