PostgreSQL: Wie werden Parameter über die Befehlszeile übergeben?

91

Ich habe eine etwas detaillierte Abfrage in einem Skript, das ?Platzhalter verwendet. Ich wollte dieselbe Abfrage direkt über die psql-Befehlszeile (außerhalb des Skripts) testen. Ich möchte vermeiden, alle ?durch tatsächliche Werte zu ersetzen , stattdessen möchte ich die Argumente nach der Abfrage übergeben.

Beispiel:

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

Auf der Suche nach etwas wie:

%> {select * from foobar where foo=? and bar=? or baz=? , 'foo','bar','baz' };
vol7ron
quelle
Bitte mehr Kontext. Befindet sich diese Abfrage in einer SQL-Datei, in einem Perl / Python / Ruby / -Skript <Lieblings-Skriptsprache hier einfügen> oder an einem anderen Ort?
@ Jack: Ich möchte dies direkt über die psql-Eingabeaufforderung (Befehlszeile) tun. Ich nehme meinen Code aus einem Skript, möchte aber nicht den gesamten Such- / Ersetzungsprozess durchlaufen.
Vol7ron
@ Vol7ron, siehe meine Antwort unten für ein psql-Befehlszeilenbeispiel.
MAbraham1
1
@ MAbraham1: schön. Ich hätte meiner Frage mehr Hintergrundwissen geben sollen. Ich habe viele Skripte, die SQL im offenen Text haben. Manchmal ist es nützlich, diese mit benutzerdefinierten Werten für das Debuggen direkt gegen die Datenbank zu drücken. Ich suchte nach einer Möglichkeit, dies in Postgres einfach zu tun, ohne zusätzliche Dateien speichern zu müssen.
Vol7ron
@ Vol7ron, danke. Ich habe über Batch-Jobs nachgedacht, aber Sie sollten die Token auch in Open SQL verwenden können. Vergiss nicht abzustimmen, wenn dir meine Antwort gefallen hat.
MAbraham1

Antworten:

178

Sie können das Konstrukt -v verwenden, z

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

und beziehen Sie sich dann auf die Variablen in SQL als: v1 ,: v2 usw.

select * from table_1 where id = :v1;

Bitte achten Sie darauf, wie wir den Zeichenfolgen- / Datumswert in zwei Anführungszeichen übergeben " '...' "

Gavin
quelle
2
+1 Interessante, benannte Argumente übergeben. Kennen Sie eine Möglichkeit, dies zu tun, sobald Sie angemeldet sind?
Vol7ron
9
Sicher, einfach benutzen \set v3 'another value'. Denken Sie daran, wenn Sie den Wert in der SQL-Anweisung zitieren müssen, verwenden Sie Apostrophe um den Variablennamen, wie SELECT * FROM foo WHERE bar = :'v3';
folgt
1
Ich denke , sie haben diese ausawk
Neil McGuigan
1
Kann @ anstelle von verwendet werden: wie sqlserver
Awais Mahmood
4
Beachten Sie, dass ich beim Lesen gehofft habe, dass mit -v gesetzte Variablen für Befehle verfügbar sind, die mit -c ausgeführt werden, aber leider nicht. Mit anderen Worten, psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" -c 'select * from table_1 where id = :v1;' wird ein Syntaxfehler generiert. Wenn Bash jedoch Ihre Shell ist, können Sie versuchen: psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" <<< 'select * from table_1 where id = :v1;' mit gutem Erfolg.
Malcook
30

In PostgreSQL haben Sie herausgefunden, dass Sie PREPAREAnweisungen genau wie in einer Skriptsprache ausführen können. Leider können Sie immer noch nicht verwenden ?, aber Sie können $nNotation verwenden.

Verwenden Sie das obige Beispiel:

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
quelle
@IvanBlack gab es noch etwas, das du damit aufnehmen wolltest? :) Die Freigabe wird automatisch am Ende einer Sitzung durchgeführt
Vol7ron
Beachten Sie nur, dass jetzt die foobeschäftigt ist und eine andere PREPAREeinen anderen Namen haben sollte, während die aktuelle Sitzung nicht geschlossen ist. Wenn Sie spielen mit PREPAREin psqles ist schwer , jedes Mal einen neuen Namen zu erfinden und DEALLOCATEdamit helfen können =)
Ivan Schwarz
Vielen Dank, dass Sie dies erwähnt haben. Ich habe PREPARE seit einiger Zeit nicht mehr verwendet, aber das sind nützliche Informationen
Vol7ron
Diese Lösung ist IMO sehr gut. Ein nützlicher Nebeneffekt: Sie können die vorbereitete Anweisung problemlos mehrmals aufrufen.
Yuri
12

In psql gibt es einen Mechanismus über die

\set name val

Befehl, der an die -v name=valBefehlszeilenoption gebunden sein soll . Das Zitieren ist schmerzhaft. In den meisten Fällen ist es einfacher, das gesamte Abfragefleisch in ein Shell-Dokument zu legen.

Bearbeiten

oops, ich hätte sagen sollen, -vanstatt -P(was für Formatierungsoptionen ist) vorherige Antwort hat es richtig gemacht.

Wildplasser
quelle
7

Sie können die Parameter auch über die psql-Befehlszeile oder aus einer Batchdatei übergeben. Die ersten Anweisungen enthalten die erforderlichen Details für die Verbindung mit Ihrer Datenbank.

Die letzte Eingabeaufforderung fragt nach den Einschränkungswerten, die in der WHERE-Spalte IN () verwendet werden. Denken Sie daran, wenn Zeichenfolgen in einfache Anführungszeichen zu setzen und durch Komma zu trennen:

@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

Fügen Sie nun in Ihrer SQL-Codedatei das v1-Token in Ihrer WHERE-Klausel oder an einer anderen Stelle in SQL hinzu. Beachten Sie, dass die Token auch in einer offenen SQL-Anweisung verwendet werden können, nicht nur in einer Datei. Speichern Sie dies als test.sql:

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

Speichern Sie unter Windows die gesamte Datei als DOS-BATch-Datei (.bat), speichern Sie die Datei test.sql im selben Verzeichnis und starten Sie die Batchdatei.

Vielen Dank für Dave Page von EnterpriseDB für das ursprünglich angeforderte Skript.

MAbraham1
quelle
+1 für das Windows-Beispiel; obwohl die meisten Pg-Datenbanken in einer * nix-Variante existieren
vol7ron
2

Es scheint, dass das, was Sie fragen, nicht direkt über die Befehlszeile ausgeführt werden kann . Sie müssen entweder eine benutzerdefinierte Funktion in plpgsql verwenden oder die Abfrage aus einer Skriptsprache aufrufen (und der letztere Ansatz erleichtert die Vermeidung von SQL-Injection ein wenig).

Gemeinschaft
quelle
War ich nicht - oft wünsche ich mir, dass Abstimmungen eine Erklärung erfordern (ähnlich wie Gründe, warum wir abstimmen, um Fragen zu schließen), auch wenn sie anonym bleiben.
Vol7ron