PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Funzione per restituire un insieme dinamico di colonne per una determinata tabella

Soluzione per il caso semplice

Come spiegato nelle risposte a cui si fa riferimento di seguito, puoi utilizzare tipi registrati (riga) e quindi dichiarare implicitamente il tipo restituito di una funzione polimorfica:

CREATE OR REPLACE FUNCTION public.get_table(_tbl_type anyelement)
  RETURNS SETOF anyelement AS
$func$
BEGIN
   RETURN QUERY EXECUTE format('TABLE %s', pg_typeof(_tbl_type));
END
$func$ LANGUAGE plpgsql;

Chiama:

SELECT * FROM public.get_table(NULL::public.users);  -- note the syntax!

Restituisce la tabella completa (con tutte le colonne utente).

Aspetta! Come?

Spiegazione dettagliata in questa risposta correlata, capitolo"Vari tipi di tabelle complete" :

  • Refactoring di una funzione PL/pgSQL per restituire l'output di varie query SELECT

TABLE foo è solo l'abbreviazione di SELECT * FROM foo :

  • C'è una scorciatoia per SELECT * FROM?

2 passaggi per un tipo di reso completamente dinamico

Ma quello che stai cercando di fare è strettamente impossibile in un singolo Comando SQL.

Voglio passare schema_name e table_name come parametri per funzionare e ottenere l'elenco dei record, secondo column_visible campo inpublic.fields tabella.

Non esiste un modo diretto per restituire una selezione arbitraria di colonne (tipo restituito non noto al momento della chiamata) da una funzione - o qualsiasi Comando SQL. SQL richiede di conoscere numero, nomi e tipi di colonne risultanti al momento della chiamata. Altro nel 2° capitolo di questa risposta correlata:

  • Come faccio a generare un CROSS JOIN con pivot in cui la definizione della tabella risultante è sconosciuta?

Esistono varie soluzioni alternative . Puoi racchiudere il risultato in uno dei tipi di documento standard (json , jsonb , hstore , xml ).

Oppure generi la query con una chiamata di funzione ed esegui il risultato con la seguente:

CREATE OR REPLACE FUNCTION public.generate_get_table(_schema_name text, _table_name text)
  RETURNS text AS
$func$
   SELECT format('SELECT %s FROM %I.%I'
               , string_agg(quote_ident(column_name), ', ')
               , schema_name
               , table_name)
   FROM   fields
   WHERE  column_visible
   AND    schema_name = _schema_name 
   AND    table_name  = _table_name
   GROUP  BY schema_name, table_name
   ORDER  BY schema_name, table_name;
$func$  LANGUAGE sql;

Chiama:

SELECT public.generate_get_table('public', 'users');

Questo crea una query del modulo:

SELECT usr_id, usr FROM public.users;

Eseguilo nel 2° passaggio. (Puoi aggiungere i numeri di colonna e ordinare le colonne.)
Oppure aggiungere \gexec in psql per eseguire immediatamente il valore restituito. Vedi:

Come forzare la valutazione della sottoquery prima di entrare / spingere verso il server esterno

Assicurati di difenderti dall'iniezione di SQL:

  • INSERT con nome tabella dinamica nella funzione trigger
  • Definire i nomi di tabelle e colonne come argomenti in una funzione plpgsql?
A parte

varchar(100) non ha molto senso per gli identificatori, che sono limitati a 63 caratteri in Postgres standard:

  • Caratteri massimi nelle etichette (nomi di tabelle, colonne, ecc.)

Se capisci come l'identificatore di oggetto digita regclass funziona, potresti sostituire lo schema e il nome della tabella con un unico regclass colonna.