Question

Dans MS SQL Server, je crée mes scripts pour utiliser des variables personnalisables :

DECLARE @somevariable int  
SELECT @somevariable = -1

INSERT INTO foo VALUES ( @somevariable )

Je vais alors changer la valeur de @somevariable au moment de l'exécution, en fonction de la valeur que je souhaite dans la situation particulière.Comme c'est en haut du script, il est facile à voir et à retenir.

Comment faire la même chose avec le client PostgreSQL psql?

Était-ce utile?

La solution

Les variables Postgres sont créées via la commande \set, par exemple...

\set myvariable value

...et peut alors être remplacé, par exemple, par ...

SELECT * FROM :myvariable.table1;

...ou ...

SELECT * FROM table1 WHERE :myvariable IS NULL;

modifier:Depuis psql 9.1, les variables peuvent être développées entre guillemets comme dans :

\set myvariable value 

SELECT * FROM table1 WHERE column1 = :'myvariable';

Dans les anciennes versions du client psql :

...Si vous souhaitez utiliser la variable comme valeur dans une requête de chaîne conditionnelle, telle que...

SELECT * FROM table1 WHERE column1 = ':myvariable';

...alors vous devez inclure les guillemets dans la variable elle-même car ce qui précède ne fonctionnera pas.Définissez plutôt votre variable comme telle...

\set myvariable 'value'

Cependant, si, comme moi, vous êtes confronté à une situation dans laquelle vous souhaitez créer une chaîne à partir d'une variable existante, j'ai trouvé que l'astuce était la suivante...

\set quoted_myvariable '\'' :myvariable '\''

Vous avez maintenant à la fois une variable entre guillemets et une variable non citée de la même chaîne !Et vous pouvez faire quelque chose comme ça....

INSERT INTO :myvariable.table1 SELECT * FROM table2 WHERE column1 = :quoted_myvariable;

Autres conseils

Un dernier mot sur les variables PSQL :

  1. Ils ne se développent pas si vous les placez entre guillemets simples dans l'instruction SQL.Donc ça ne marche pas :

    SELECT * FROM foo WHERE bar = ':myvariable'
    
  2. Pour développer une chaîne littérale dans une instruction SQL, vous devez inclure les guillemets dans l'ensemble de variables.Cependant, la valeur de la variable doit déjà être placée entre guillemets, ce qui signifie que vous avez besoin d'un deuxième ensemble de guillemets, et l’ensemble interne doit être échappé.Il vous faut donc :

    \set myvariable '\'somestring\''  
    SELECT * FROM foo WHERE bar = :myvariable
    

    MODIFIER:à partir de PostgreSQL 9.1, vous pouvez écrire à la place :

    \set myvariable somestring
    SELECT * FROM foo WHERE bar = :'myvariable'
    

Vous pouvez essayer d'utiliser un AVEC clause.

WITH vars AS (SELECT 42 AS answer, 3.14 AS appr_pi)
SELECT t.*, vars.answer, t.radius*vars.appr_pi
FROM table AS t, vars;

Spécifiquement pour psql, tu peux passer psql les variables de la ligne de commande également ;tu peux les passer avec -v.Voici un exemple d'utilisation :

$ psql -v filepath=/path/to/my/directory/mydatafile.data regress
regress=> SELECT :'filepath';
               ?column?                
---------------------------------------
 /path/to/my/directory/mydatafile.data
(1 row)

Notez que les deux points ne sont pas entre guillemets, alors le nom de la variable lui-même est entre guillemets.Syntaxe étrange, je sais.Cela ne fonctionne qu'avec psql ;cela ne fonctionnera pas dans (disons) PgAdmin-III.

Cette substitution se produit lors du traitement des entrées dans psql, vous ne pouvez donc pas (par exemple) définir une fonction qui utilise :'filepath' et attendez la valeur de :'filepath' pour changer de séance en séance.Il sera remplacé une fois, lorsque la fonction est définie, puis sera une constante par la suite.C'est utile pour les scripts mais pas pour l'exécution.

FWIW, le vrai problème était que j'avais inclus un point-virgule à la fin de ma commande \set :

\set Owner_password 'le mot de passe';

Le point-virgule a été interprété comme un caractère réel dans la variable :

echo: propriétaire_password thepassword;

Alors quand j'ai essayé de l'utiliser :

CREATE ROLE myrole CONNEXION MOT DE PASSE NON CRYPTÉ :owner_password NOINHERIT CREATEDB CREATEROLE VALIDE JUSQU'À 'infini';

...J'ai eu ceci :

CRÉER UN RÔLE mon rôle CONNEXION MOT DE PASSE NON CRYPTÉ thepassword;NOINHERIT CREATEDB CREATEROLE VALABLE JUSQU'À 'l'infini';

Cela non seulement n'a pas réussi à définir les guillemets autour du littéral, mais a également divisé la commande en 2 parties (dont la seconde n'était pas valide car elle commençait par "NOINHERIT").

La morale de cette histoire:Les "variables" PostgreSQL sont en réalité des macros utilisées dans l'expansion de texte, pas de vraies valeurs.Je suis sûr que c'est utile, mais c'est délicat au début.

Vous devez utiliser l'un des langages procéduraux tels que PL/pgSQL et non le langage proc SQL.En PL/pgSQL, vous pouvez utiliser les variables directement dans les instructions SQL.Pour les guillemets simples, vous pouvez utiliser la fonction littérale quote.

postgres (depuis la version 9.0) autorise les blocs anonymes dans n'importe lequel des langages de script côté serveur pris en charge

DO '
DECLARE somevariable int = -1;
BEGIN
INSERT INTO foo VALUES ( somevariable );
END
' ;

http://www.postgresql.org/docs/current/static/sql-do.html

Comme tout se trouve dans une chaîne, les variables de chaîne externes remplacées devront être échappées et citées deux fois.L'utilisation de citations en dollars à la place n'offrira pas une protection complète contre l'injection SQL.

Une autre approche consiste à (ab)utiliser le mécanisme PostgreSQL GUC pour créer des variables.Voir cette réponse préalable pour plus de détails et d'exemples.

Vous déclarez le GUC dans postgresql.conf, puis modifiez sa valeur au moment de l'exécution avec SET commandes et obtenir sa valeur avec current_setting(...).

Je ne le recommande pas pour un usage général, mais cela pourrait être utile dans des cas précis comme celui mentionné dans la question liée, où l'affiche souhaitait un moyen de fournir le nom d'utilisateur au niveau de l'application aux déclencheurs et aux fonctions.

Je l'ai résolu avec une table temporaire.

CREATE TEMP TABLE temp_session_variables (
    "sessionSalt" TEXT
);
INSERT INTO temp_session_variables ("sessionSalt") VALUES (current_timestamp || RANDOM()::TEXT);

De cette façon, j'avais une "variable" que je pouvais utiliser sur plusieurs requêtes, unique pour la session.J'en avais besoin pour générer des "noms d'utilisateur" uniques tout en évitant les collisions lors de l'importation d'utilisateurs avec le même nom d'utilisateur.

J'ai trouvé cette question et les réponses extrêmement utiles, mais aussi déroutantes.J'ai eu beaucoup de mal à faire fonctionner les variables citées, alors voici comment je l'ai fait fonctionner :

\set deployment_user username    -- username
\set deployment_pass '\'string_password\''
ALTER USER :deployment_user WITH PASSWORD :deployment_pass;

De cette façon, vous pouvez définir la variable dans une seule instruction.Lorsque vous l'utilisez, des guillemets simples seront intégrés dans la variable.

NOTE!Lorsque j'ai mis un commentaire après la variable citée, il a été intégré à la variable lorsque j'ai essayé certaines méthodes dans d'autres réponses.Cela m'a vraiment fait chier pendant un moment.Avec cette méthode, les commentaires semblent être traités comme prévu.

Cette fonctionnalité me manque vraiment.La seule façon d’obtenir quelque chose de similaire est d’utiliser des fonctions.

Je l'ai utilisé de deux manières :

  • fonctions Perl qui utilisent la variable $_SHARED
  • stockez vos variables dans un tableau

Version Perl :

   CREATE FUNCTION var(name text, val text) RETURNS void AS $$
        $_SHARED{$_[0]} = $_[1];
   $$ LANGUAGE plperl;
   CREATE FUNCTION var(name text) RETURNS text AS $$
        return $_SHARED{$_[0]};
   $$ LANGUAGE plperl;

Version tableau :

CREATE TABLE var (
  sess bigint NOT NULL,
  key varchar NOT NULL,
  val varchar,
  CONSTRAINT var_pkey PRIMARY KEY (sess, key)
);
CREATE FUNCTION var(key varchar, val anyelement) RETURNS void AS $$
  DELETE FROM var WHERE sess = pg_backend_pid() AND key = $1;
  INSERT INTO var (sess, key, val) VALUES (sessid(), $1, $2::varchar);
$$ LANGUAGE 'sql';

CREATE FUNCTION var(varname varchar) RETURNS varchar AS $$
  SELECT val FROM var WHERE sess = pg_backend_pid() AND key = $1;
$$ LANGUAGE 'sql';

Remarques:

  • plperlu est plus rapide que Perl
  • pg_backend_pid n'est pas la meilleure identification de session, pensez à utiliser pid combiné avec backend_start de pg_stat_activity
  • cette version de table est également mauvaise car vous devez effacer cela de temps en temps (et ne pas supprimer les variables de session en cours de travail)

Variables dans psql sucer.Si vous souhaitez déclarer un entier, vous devez saisir l'entier, puis effectuer un retour chariot, puis terminer l'instruction par un point-virgule.Observer:

Disons que je veux déclarer une variable entière my_var et insérez-le dans un tableau test:

Exemple de tableau test:

thedatabase=# \d test;
                         Table "public.test"
 Column |  Type   |                     Modifiers                     
--------+---------+---------------------------------------------------
 id     | integer | not null default nextval('test_id_seq'::regclass)
Indexes:
    "test_pkey" PRIMARY KEY, btree (id)

En clair, rien dans ce tableau pour l'instant :

thedatabase=# select * from test;
 id 
----
(0 rows)

Nous déclarons une variable. Remarquez comment se trouve le point-virgule sur la ligne suivante !

thedatabase=# \set my_var 999
thedatabase=# ;

Nous pouvons maintenant insérer.Nous devons utiliser ce bizarre ":''" syntaxe recherchée :

thedatabase=# insert into test(id) values (:'my_var');
INSERT 0 1

Ça a marché!

thedatabase=# select * from test;
 id  
-----
 999
(1 row)

Explication:

Donc...que se passe-t-il si nous n'avons pas de point-virgule sur la ligne suivante ?La variable ?Regarde:

Nous déclarons my_var sans la nouvelle ligne.

thedatabase=# \set my_var 999;

Sélectionnons my_var.

thedatabase=# select :'my_var';
 ?column? 
----------
 999;
(1 row)

WTF, c'est ça ?Ce n'est pas un entier, c'est un chaîne 999;!

thedatabase=# select 999;
 ?column? 
----------
      999
(1 row)

J'ai publié une nouvelle solution pour cela sur un autre fil.

Il utilise une table pour stocker les variables et peut être mis à jour à tout moment.Une fonction getter statique immuable est créée dynamiquement (par une autre fonction), déclenchée par la mise à jour de votre table.Vous bénéficiez d'un joli stockage de table, ainsi que des vitesses fulgurantes d'un getter immuable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top