PostgreSQL: comment passer des paramètres depuis la ligne de commande?

92

J'ai une requête un peu détaillée dans un script qui utilise des ?espaces réservés. Je voulais tester cette même requête directement depuis la ligne de commande psql (en dehors du script). Je veux éviter d'entrer et de remplacer tous les ?par des valeurs réelles, au lieu de cela, j'aimerais passer les arguments après la requête.

Exemple:

SELECT  * 
FROM    foobar
WHERE   foo = ?
   AND  bar = ?
    OR  baz = ?  ;

Vous cherchez quelque chose comme:

%> {select * from foobar where foo=? and bar=? or baz=? , 'foo','bar','baz' };
vol7ron
la source
Plus de contexte, s'il vous plaît. Cette requête se trouve-t-elle dans un fichier SQL, dans un script Perl / Python / Ruby / <insérer le langage de script favori ici>, ou à un autre endroit?
@Jack: Je cherche à faire cela directement à partir de l'invite psql (ligne de commande). Je prends mon code d'un script, mais je ne veux pas passer par tout le processus de recherche / remplacement.
vol7ron le
@ Vol7ron, veuillez voir ma réponse ci-dessous pour un exemple de ligne de commande psql.
MAbraham1
1
@ MAbraham1: sympa. J'aurais dû donner un peu plus de contexte à ma question. J'ai beaucoup de scripts qui ont SQL en texte ouvert. Parfois, il est utile de les prendre et de les frapper directement contre la base de données, avec des valeurs personnalisées pour le débogage. Je cherchais un moyen de le faire facilement dans Postgres sans avoir besoin d'enregistrer des fichiers supplémentaires.
vol7ron
@ Vol7ron, merci. Je pensais en termes de travaux par lots, mais vous devriez également pouvoir utiliser les jetons dans Open SQL. N'oubliez pas de voter si vous avez aimé ma réponse.
MAbraham1

Réponses:

178

Vous pouvez utiliser la construction -v par exemple

psql -v v1=12  -v v2="'Hello World'" -v v3="'2010-11-12'"

puis faites référence aux variables dans sql comme suit: v1,: v2 etc.

select * from table_1 where id = :v1;

Veuillez faire attention à la façon dont nous transmettons la valeur de chaîne / date en utilisant deux guillemets " '...' "

Gavin
la source
2
+1 Intéressant, passant des arguments nommés. Connaissez-vous un moyen de le faire une fois connecté?
vol7ron le
9
Bien sûr, utilisez simplement \set v3 'another value'. N'oubliez pas que lorsque vous devez citer la valeur dans une instruction SQL, utilisez des apostrophes autour du nom de la variable, comme ceci:SELECT * FROM foo WHERE bar = :'v3';
Cromax
1
Je suppose qu'ils l'ont obtenu deawk
Neil McGuigan
1
Peut être utilisé à la place de: comme sqlserver
Awais Mahmood
4
Notez qu'en lisant ceci, j'espérais trouver que les variables définies avec -v seraient disponibles pour les commandes exécutées avec -c, mais hélas elles ne le sont pas. En d'autres termes, psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" -c 'select * from table_1 where id = :v1;' générera une erreur de syntaxe. Cependant, si bash est votre shell, vous pouvez essayer: psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" <<< 'select * from table_1 where id = :v1;' avec succès.
malcook
30

Trouvé dans PostgreSQL, vous pouvez faire des PREPAREdéclarations comme vous pouvez le faire dans un langage de script. Malheureusement, vous ne pouvez toujours pas utiliser ?, mais vous pouvez utiliser la $nnotation.

En utilisant l'exemple ci-dessus:

PREPARE foo(text,text,text) AS
    SELECT  * 
    FROM    foobar
    WHERE   foo = $1
       AND  bar = $2
        OR  baz = $3  ;
EXECUTE foo('foo','bar','baz');
DEALLOCATE foo;
vol7ron
la source
@IvanBlack y avait-il autre chose que vous vouliez inclure avec ça? :) la désallocation est effectuée automatiquement à la fin d'une session
vol7ron
Notez simplement que maintenant le fooest occupé et un autre PREPAREdevrait avoir un autre nom alors que la session en cours n'est pas fermée. Si vous jouez avec PREPAREdans psqlil est difficile d'inventer à chaque fois un nouveau nom et DEALLOCATEpeut aider avec elle =)
Ivan Noir
Merci d'avoir mentionné cela. Je n'ai pas utilisé PREPARE depuis un certain temps, mais ce sont des informations utiles
vol7ron
Cette solution est très bonne IMO. Un effet secondaire utile - vous pouvez facilement appeler l'instruction préparée plusieurs fois.
Yuri
13

Dans psql, il existe un mécanisme via le

\set name val

commande, qui est censée être liée au -v name=val option de ligne de commande. La citation est pénible, dans la plupart des cas, il est plus facile de mettre toute la viande de requête dans un shell ici-document.

Éditer

oups, j'aurais dû dire -vau lieu de -P(ce qui est pour les options de formatage) la réponse précédente avait raison.

wildplasser
la source
7

Vous pouvez également transmettre les paramètres sur la ligne de commande psql ou à partir d'un fichier de commandes. Les premières instructions rassemblent les détails nécessaires à la connexion à votre base de données.

La dernière invite demande les valeurs de contrainte, qui seront utilisées dans la clause WHERE colonne IN (). N'oubliez pas de placer les chaînes entre guillemets simples et séparez-les par une virgule:

@echo off
echo "Test for Passing Params to PGSQL"
SET server=localhost
SET /P server="Server [%server%]: "

SET database=amedatamodel
SET /P database="Database [%database%]: "

SET port=5432
SET /P port="Port [%port%]: "

SET username=postgres
SET /P username="Username [%username%]: "

SET /P bunos="Enter multiple constraint values for IN clause [%constraints%]: "
ECHO you typed %constraints%
PAUSE
REM pause
"C:\Program Files\PostgreSQL\9.0\bin\psql.exe" -h %server% -U %username% -d %database% -p %port% -e -v v1=%constraints% -f test.sql

Maintenant, dans votre fichier de code SQL, ajoutez le jeton v1 dans votre clause WHERE, ou n'importe où ailleurs dans le SQL. Notez que les jetons peuvent également être utilisés dans une instruction SQL ouverte, pas seulement dans un fichier. Enregistrez-le sous test.sql:

SELECT * FROM myTable
WHERE NOT someColumn IN (:v1);

Sous Windows, enregistrez le fichier entier en tant que fichier DOS BATch (.bat), enregistrez le test.sql dans le même répertoire et lancez le fichier de commandes.

Merci à Dave Page, d'EnterpriseDB, pour le script original.

MAbraham1
la source
+1 pour l'exemple Windows; bien que la plupart des bases de données Pg existent dans une variante * nix
vol7ron
2

Il semblerait que ce que vous demandez ne peut pas être fait directement à partir de la ligne de commande . Vous devrez soit utiliser une fonction définie par l'utilisateur dans plpgsql, soit appeler la requête à partir d'un langage de script (et cette dernière approche permet d'éviter un peu plus facilement l'injection SQL).

Communauté
la source
N'était-ce pas moi - je souhaite souvent que les votes négatifs nécessitent une sorte d'explication (similaire aux raisons pour lesquelles nous votons pour clore les questions), même si elles sont laissées de manière anonyme.
vol7ron