Chamando procedimentos ou funções PostgreSQL do Query Builder do QGIS

Oct 18 2020

Estou tentando chamar um procedimento armazenado ou função definida no banco de dados PostgreSQL / PostGIS e usá-lo a partir do QGIS Query Builder. Nenhum trabalho:

  • a função retorna uma tabela que não pode ser interpretada pelo Query Builder
  • o procedimento, que retorna uma seleção, falha quando eu o chamo usando a callinstrução

Ambos funcionam bem no DataGrip e consultam uma tag de uma tagcoluna de matriz de texto na waypointstabela.

Aqui está a função:

create or replace function gwd(t text)
RETURNS TABLE (f_ogc_fid int, f_name text)
LANGUAGE plpgsql
AS $$ BEGIN return query SELECT ogc_fid,name::text FROM gis.gps.waypoints where tag @> STRING_TO_ARRAY(t, ','); end; $$

Aqui está o procedimento que falha no CALLQuery Builder do QGIS:

create or replace procedure grw(T text)
LANGUAGE plpgsql
AS $$ BEGIN SELECT * FROM gis.gps.waypoints where tag @> STRING_TO_ARRAY(T, ','); end; $$

Aqui está o erro relatado pelo QGis quando executo call grw('iron')no Query Builder:

An error occurred when executing the query.
The data provider said:
ERROR:  syntax error at or near "grw"
LINE 1: SELECT * FROM "gps"."waypoints" WHERE call grw('iron') LIMIT...

Quando eu ligo sem o CALL, também não funciona:

An error occurred when executing the query.
The data provider said:
ERROR:  grw(unknown) is a procedure
LINE 1: SELECT * FROM "gps"."waypoints" WHERE grw('iron') LIMIT 0
HINT:  To call a procedure, use CALL.

Respostas

1 geozelot Oct 19 2020 at 09:56

Três coisas:

  • A PRODECUREé uma instrução de procedimento ciente de transação , introduzida no PG 11, para acomodar o controle de transação ausente em um FUNCTIONbloco normal .

    No entanto , a PROCEDURE não pode retornar valores e qualquer outra coisa senão chamá-lo diretamente com ( nada além de )

    CALL <procedure>;
    

    Não pode trabalhar. Você deseja usar um PROCEDUREsempre que desejar executar instruções DDL em suas relações com o controle de transação , enquanto lida com erros durante a execução de forma mais elegante. Semanticamente, o que você está procurando é umFUNCTION

  • A caixa de diálogo Construtor de consultas permite adicionar rapidamente expressões de filtro na fonte de dados.

    No entanto , o QGIS traduz esses filtros em sintaxe específica do provedor , o que significa que, no caso de uma camada de origem PostgreSQL / PostGIS, ele adicionará essas instruções a uma consulta de base na forma de

    SELECT * FROM "<schema>"."<table>" WHERE <FILTER>;
    

    onde <FILTER>é a expressão precisa inserida no campo de diálogo

  • De qualquer forma, suas tentativas são inúteis (sem ofensa) para a maneira como você pretende usá-las:

    • não faz sentido filtrar uma tabela por uma tag para usar as linhas / valores retornados como o mesmo filtro para a mesma tabela
    • e se você quiser fazer isso, precisará definir novamente uma expressão de filtro para usar as linhas / valores retornados

A solução mais simples seria apenas ( e apenas ) inserir

'iron' = ANY(tag)

no campo Expressão do construtor de consulta ; isso se traduz em

SELECT * FROM "gps"."waypoints" WHERE 'iron' = ANY(tag);

que você pode usar no SQL diretamente, se necessário.