PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

SELECT colunas dinâmicas sem funções no PostgreSQL


O que você está tentando fazer dificilmente é possível em sua totalidade.

Criar SQL dinâmico


Primeiro, veja o que você pode do:uma função plpgsql que cria o SQL para tal consulta:
CREATE OR REPLACE FUNCTION f_union_common_col_sql(text, text)
 RETURNS text
AS $function$
DECLARE 
  _cols text;
BEGIN

_cols := string_agg(attname, ', ')
FROM (
    SELECT a.attname
    FROM   pg_attribute a
    WHERE  a.attrelid = $1::regclass::oid
    AND    a.attnum >= 1
    INTERSECT
    SELECT a.attname
    FROM   pg_attribute a
    WHERE  a.attrelid = $2::regclass::oid
    AND    a.attnum >= 1
    ) x;

RETURN 'SELECT ' || _cols || '
FROM   ' || quote_ident($1) || '
UNION
SELECT ' || _cols || '
FROM   ' || quote_ident($1);

END;
$function$  LANGUAGE plpgsql;

COMMENT ON FUNCTION f_union_common_col_sql(text, text) IS 'Create SQL to query all visible columns that two tables have in common.
# Without duplicates. Use UNION ALL if you want to include duplicates.
# Depends on visibility dicatated by search_path
$1 .. table1: optionally schema-qualified, case sensitive!
$2 .. table2: optionally schema-qualified, case sensitive!';

Ligar:
SELECT f_union_common_col_sql('myschema1.tbl1', 'myschema2.tbl2');

Dá-lhe a consulta completa. Execute-o em uma segunda chamada.

Você pode encontrar quase tudo o que usei aqui no manual de funções plpgsql .
A função agregada string_agg() foi introduzido com o PostgreSQL 9.0. Em versões mais antigas você faria:array_to_string(array_agg(attname), ', ') .

Executar SQL dinâmico?


Em seguida, aqui está o que você dificilmente pode Faz:
CREATE OR REPLACE FUNCTION f_union_common_col(text, text)
  RETURNS SETOF record AS
$BODY$
DECLARE 
  _cols text;
BEGIN

_cols := string_agg(attname, ', ')
FROM (
    SELECT a.attname
    FROM   pg_attribute a
    WHERE  a.attrelid = $1::regclass::oid
    AND    a.attnum >= 1
    INTERSECT
    SELECT a.attname
    FROM   pg_attribute a
    WHERE  a.attrelid = $2::regclass::oid
    AND    a.attnum >= 1
    ) x;

RETURN QUERY EXECUTE '
SELECT ' || _cols || '
FROM quote_ident($1)
UNION
SELECT ' || _cols || '
FROM quote_ident($2)';

END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

COMMENT ON FUNCTION f_union_common_col(text, text) IS 'Query all visible columns that two tables have in common.
# Without duplicates. Use UNION ALL if you want to include duplicates.
# Depends on visibility dicatated by search_path
# !BUT! you need to specify a column definition list for every call. So, hardly useful.
$1 .. table1 (optionally schema-qualified)
$2 .. table1 (optionally schema-qualified)';

Uma chamada de função requer que você especifique a lista de colunas de destino. então isso dificilmente é útil:
SELECT * from f_union_common_col('myschema1.tbl1', 'myschema2.tbl2')

ERROR:  a column definition list is required for functions returning "record"

Não há uma maneira fácil de contornar isso. Você teria que criar dinamicamente uma função ou pelo menos um tipo complexo. É aqui que eu paro.