web-dev-qa-db-fra.com

Postgres plpgsql - Utilisation d'une variable à l'intérieur d'une instruction create dynamique

En utilisant Postgres pl/pgsql, j'essaie de créer une table à l'aide d'une commande EXECUTE dynamique, telle que:

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

Cependant, je continue de recevoir le message d'erreur

ERREUR: erreur de syntaxe à ou près de "$ 1"

Si je n'utilise pas le $1 token et, à la place, écrivez la chaîne myTable cela fonctionne très bien.

Existe-t-il une limitation à l'utilisation des instructions dynamiques pour les appels CREATE?

8
Jmoney38

En plus de ce que @filiprem a écrit, voici comment procéder correctement:

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

Utilisez quote_ident() pour éviter les erreurs d'injection SQL ou de syntaxe. Il cite des noms avec des caractères non standard ou des mots réservés.

J'ai également remplacé les guillemets doubles que vous aviez autour de la valeur de chaîne dans votre exemple par guillemets simples .

5
Erwin Brandstetter

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

Notez que les symboles de paramètre ne peuvent être utilisés que pour les valeurs de données - si vous souhaitez utiliser des noms de table ou de colonne déterminés dynamiquement, vous devez les insérer textuellement dans la chaîne de commande. Par exemple, si la requête précédente devait être effectuée sur une table sélectionnée dynamiquement, vous pouvez le faire:

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

Comme indiqué dans les commentaires ci-dessous, la méthode de conversion n'est pas toujours possible, en particulier pour les instructions CREATE. Considérez la fonction format, par exemple:

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

En d'autres termes:

Oui, il y a une telle limitation. Vous ne pouvez pas utiliser de paramètres pour les noms de table/colonne, car Postgresql doit pouvoir analyser la requête lors de la compilation de l'instruction SQL dynamique. L'analyseur doit être capable d'identifier les relations utilisées.

Note latérale: cette limitation s'applique probablement au SQL dynamique dans d'autres SGBD, y compris Oracle: http://download.Oracle.com/docs/cd/B19306_01/appdev.102/b14261/dynamic.htm#CHDHGHIF =

3
filiprem