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

Esecuzione di query dinamicamente in PL/pgSQL

Statistiche di sistema

Prima di fare il tuo, dai un'occhiata alla tabella di sistema pg_statistic o la vista pg_stats :

Potrebbe già avere alcune delle statistiche che stai per calcolare. È popolato da ANALYZE , quindi potresti eseguirlo per nuove (o qualsiasi) tabelle prima di controllare.

-- ANALYZE tbl;  -- optionally, to init / refresh
SELECT * FROM pg_stats
WHERE tablename = 'tbl'
AND   schemaname = 'public';

Funzione plpgsql dinamica generica

Vuoi restituire il valore minimo per ogni colonna in una determinata tabella . Questo non è un compito banale, perché una funzione (come SQL in generale) richiede di conoscere il tipo restituito al momento della creazione, o almeno al momento della chiamata con l'aiuto di tipi di dati polimorfici.

Questa funzione fa tutto in modo automatico e sicuro. Funziona per qualsiasi tabella, purché la funzione di aggregazione min() è consentito per ogni colonna. Ma tu hai bisogno per conoscere PL/pgSQL.

CREATE OR REPLACE FUNCTION f_min_of(_tbl anyelement)
  RETURNS SETOF anyelement
  LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE (
   SELECT format('SELECT (t::%2$s).* FROM (SELECT min(%1$s) FROM %2$s) t'
                , string_agg(quote_ident(attname), '), min(' ORDER BY attnum)
                , pg_typeof(_tbl)::text)
   FROM   pg_attribute
   WHERE  attrelid = pg_typeof(_tbl)::text::regclass
   AND    NOT attisdropped  -- no dropped (dead) columns
   AND    attnum > 0        -- no system columns
   );
END
$func$;

Chiama (importante!):

SELECT * FROM f_min_of(NULL::tbl);  -- tbl being the table name

db<>violino qui
Vecchio sqlfiddle

Devi comprendere questi concetti:

  • SQL dinamico in plpgsql con EXECUTE
  • Tipi polimorfici
  • Tipi di riga e tipi di tabella in Postgres
  • Come difendersi da SQL injection
  • Funzioni aggregate
  • Cataloghi di sistema

Risposta correlata con spiegazione dettagliata:

Difficoltà speciale con tipo non corrispondente

Sto sfruttando Postgres per definire un tipo di riga per ogni tabella esistente. Utilizzando il concetto di tipi polimorfici sono in grado di crearne uno funzione che funziona per qualsiasi tabella.

Tuttavia, alcune funzioni di aggregazione restituiscono tipi di dati correlati ma diversi rispetto alla colonna sottostante. Ad esempio, min(varchar_column) restituisce text , che è compatibile con i bit, ma non esattamente lo stesso tipo di dati. Le funzioni PL/pgSQL hanno qui un punto debole e insistono sui tipi di dati esattamente come dichiarato nel RETURNS clausola. Nessun tentativo di cast, nemmeno impliciti, per non parlare di cast di assegnazione.

Dovrebbe essere migliorato. Testato con Postgres 9.3. Non ho ripetuto il test con 9.4, ma sono abbastanza sicuro che non è cambiato nulla in quest'area.

È qui che entra in gioco questo costrutto come soluzione alternativa :

SELECT (t::tbl).* FROM (SELECT ... FROM tbl) t;

Trasmettendo in modo esplicito l'intera riga al tipo di riga della tabella sottostante, forziamo i cast di assegnazione per ottenere i tipi di dati originali per ogni colonna.

Questo potrebbe non riuscire per alcune funzioni aggregate. sum() restituisce numeric per un sum(bigint_column) per accogliere una somma eccedente il tipo di dati di base. Ritorno a bigint potrebbe non riuscire...