sql >> Databasteknik >  >> RDS >> PostgreSQL

VÄLJ dynamiska kolumner utan funktioner i PostgreSQL

Det du försöker göra är knappast möjligt i sin helhet.

Skapa dynamisk SQL

Först, här är vad du kan do:en plpgsql-funktion som skapar SQL för en sådan fråga:

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

Ring:

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

Ger dig hela frågan. Kör det i ett andra samtal.

Du kan hitta det mesta jag använde här i manualen om plpgsql-funktioner .
aggregationsfunktionen string_agg() introducerades med PostgreSQL 9.0. I äldre versioner skulle du:array_to_string(array_agg(attname), ', ') .

Kör dynamisk SQL?

Nästa, här är vad du knappast kan gör:

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

Ett funktionsanrop kräver att du anger listan med målkolumner. så det här är knappast användbart alls:

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

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

Det finns ingen enkel väg runt detta. Du måste dynamiskt skapa en funktion eller åtminstone en komplex typ. Det är här jag slutar.




  1. Beräkna den totala tidslängden på sista raden i mysql

  2. Hur man beräknar omvandlingsfrekvens i MySQL?

  3. Klienten stöder inte autentiseringsprotokoll som begärts av servern

  4. MySQL till PostgreSQL-tabell skapar konvertering - teckenuppsättning och sortering