PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

SELECT dynamische Spalten ohne Funktionen in PostgreSQL

Was Sie vorhaben, ist in seiner Gesamtheit kaum möglich.

Dynamisches SQL erstellen

Hier ist zunächst, was Sie können do:eine plpgsql-Funktion, die die SQL für eine solche Abfrage erstellt:

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!';

Aufruf:

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

Gibt Ihnen die vollständige Abfrage. Führen Sie es in einem zweiten Aufruf aus.

Fast alles, was ich hier verwendet habe, finden Sie im Handbuch zu plpgsql-Funktionen .
Die Aggregatfunktion string_agg() wurde mit PostgreSQL 9.0 eingeführt. In älteren Versionen würden Sie:array_to_string(array_agg(attname), ', ') .

Dynamisches SQL ausführen?

Als nächstes ist hier, was Sie kaum können tun:

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

Für einen Funktionsaufruf müssen Sie die Liste der Zielspalten angeben. das ist also kaum sinnvoll:

SELECT * from f_union_common_col('myschema1.tbl1', 'myschema2.tbl2')

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

Es gibt keinen einfachen Weg, dies zu umgehen. Sie müssten dynamisch eine Funktion oder zumindest einen komplexen Typ erstellen. Hier höre ich auf.