it-swarm.it

Postgres plpgsql - Utilizzo di una variabile all'interno di un'istruzione di creazione dinamica

Usando Postgres pl/pgsql, sto tentando di creare una tabella usando un comando EXECUTE dinamico, come:

 ...
 DECLARE
    tblVar varchar := "myTable";
 BEGIN
 EXECUTE 'CREATE TABLE $1 ( 
             foo integer NOT NULL, 
             bar varchar NOT NULL)'
 USING _tblVar;
 ...

Tuttavia, continuo a ricevere il messaggio di errore

ERRORE: errore di sintassi pari o vicino a "$ 1"

Se non uso $1 token e, invece, scrivi la stringa myTable funziona perfettamente.

Esiste una limitazione all'uso delle istruzioni dinamiche per le chiamate CREATE?

8
Jmoney38

Oltre a ciò che ha scritto @filiprem, ecco come farlo correttamente:

...
DECLARE
   tbl_var text := 'myTable';   -- I would not use mixed case names ..
BEGIN
EXECUTE '
CREATE TABLE ' || quote_ident(tbl_var) || '( 
   foo integer NOT NULL, 
   bar text NOT NULL)';
...

Utilizzare quote_ident() per evitare l'iniezione SQL o errori di sintassi. Citerà i nomi con caratteri non standard o parole riservate.

Ho anche sostituito le virgolette doppie che avevi intorno al valore di stringa nel tuo esempio con virgolette singole .

5

Vedi http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN

Si noti che i simboli dei parametri possono essere utilizzati solo per i valori dei dati: se si desidera utilizzare nomi di tabelle o colonne determinati dinamicamente, è necessario inserirli testualmente nella stringa di comando. Ad esempio, se è necessario eseguire la query precedente su una tabella selezionata dinamicamente, è possibile effettuare ciò:

EXECUTE 'SELECT count(*) FROM '
    || tabname::regclass
    || ' WHERE inserted_by = $1 AND inserted <= $2'
   INTO c
   USING checked_user, checked_date;

Come notato nei commenti seguenti, il metodo cast non è sempre fattibile, specialmente per le istruzioni CREATE. Considera la funzione format, ad esempio:

EXECUTE format(
  'CREATE TABLE %I (%I %I, %I %I)',
  v_tabname,
  v_col1name, v_col1type,
  v_col2name, v_col2type);

In altre parole:

Sì, esiste una tale limitazione. Non è possibile utilizzare i parametri per i nomi di tabella/colonna, poiché Postgresql deve essere in grado di analizzare la query durante la compilazione dell'istruzione SQL dinamica. Il parser deve essere in grado di identificare le relazioni utilizzate.

Nota a margine: probabilmente questa limitazione si applica a SQL dinamico in altri DBMS, incluso Oracle: http://download.Oracle.com/docs/cd/B19306_01/appdev.102/b14261/dynamic.htm#CHDHGHIF =

3
filiprem