PostgreSQL: Jak przekazać parametry z wiersza poleceń?

95

Mam dość szczegółowe zapytanie w skrypcie, który używa ?symboli zastępczych. Chciałem przetestować to samo zapytanie bezpośrednio z wiersza poleceń psql (poza skryptem). Chcę uniknąć wchodzenia i zastępowania wszystkich ?rzeczywistymi wartościami, zamiast tego chciałbym przekazać argumenty po zapytaniu.

Przykład:

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

Szukam czegoś takiego:

%> {select * from foobar where foo=? and bar=? or baz=? , 'foo','bar','baz' };
vol7ron
źródło
Poproszę więcej kontekstu. Czy to zapytanie znajduje się w pliku SQL, w skrypcie Perl / Python / Ruby / <tu wstaw ulubiony język skryptowy>, czy w jakimś innym miejscu?
@Jack: Chcę to zrobić bezpośrednio z wiersza poleceń psql (wiersz poleceń). Pobieram kod ze skryptu, ale nie chcę przechodzić przez cały proces znajdowania / zastępowania.
vol7ron
@ Vol7ron, zobacz moją odpowiedź poniżej na przykład wiersza poleceń psql.
MAbraham1
1
@ MAbraham1: fajnie. Powinienem był podać więcej informacji na temat mojego pytania. Mam wiele skryptów, które mają SQL w otwartym tekście. Czasami warto je wziąć i trafić bezpośrednio do bazy danych, z niestandardowymi wartościami do debugowania. Szukałem sposobu na łatwe zrobienie tego w Postgres bez konieczności zapisywania dodatkowych plików.
vol7ron
@ Vol7ron, dzięki. Myślałem o zadaniach wsadowych, jednak powinieneś móc używać tokenów również w otwartym SQL. Nie zapomnij oddać głosu, jeśli spodobała Ci się moja odpowiedź.
MAbraham1

Odpowiedzi:

181

Możesz użyć konstrukcji -v np

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

a następnie odwołaj się do zmiennych w sql jako: v1,: v2 itd

select * from table_1 where id = :v1;

Zwróć uwagę na sposób przekazywania wartości ciągu / daty w dwóch cudzysłowach " '...' "

Gavin
źródło
2
+1 Ciekawe, przekazywanie nazwanych argumentów. Czy znasz jakiś sposób, aby to zrobić po zalogowaniu?
vol7ron
9
Jasne, po prostu użyj \set v3 'another value'. Pamiętaj tylko, że kiedy musisz zacytować wartość w instrukcji SQL, użyj apostrofów wokół nazwy zmiennej, na przykład:SELECT * FROM foo WHERE bar = :'v3';
Cromax,
2
Myślę, że dostali to odawk
Neila McGuigana
1
Można użyć @ zamiast: jak sqlserver
Awais Mahmood,
5
Zauważ, że po przeczytaniu tego miałem nadzieję, że zmienne ustawione za pomocą -v będą dostępne dla poleceń wykonywanych z -c, ale niestety tak nie jest. Innymi słowy, psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" -c 'select * from table_1 where id = :v1;' wygeneruje błąd składniowy. Jeśli jednak bash jest twoją powłoką, możesz spróbować: psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" <<< 'select * from table_1 where id = :v1;' z dobrym skutkiem.
malcook
31

Dowiedział się w PostgreSQL, możesz wyciągać PREPAREoświadczenia tak samo, jak w języku skryptowym. Niestety nadal nie możesz użyć ?, ale możesz użyć $nnotacji.

Korzystając z powyższego przykładu:

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
źródło
@IvanBlack Czy było coś jeszcze, co chciałeś do tego dołączyć? :)
cofnięcie alokacji
Zwróć uwagę, że teraz foojest zajęty, a inny PREPAREpowinien mieć inną nazwę, podczas gdy bieżąca sesja nie jest zamknięta. Jeśli grasz PREPAREw psqlto, trudno jest wymyślić za każdym razem nową nazwę i DEALLOCATEmożesz w tym pomóc =)
Ivan Black
Dzięki za wspomnienie o tym. Od jakiegoś czasu nie korzystałem z PREPARE, ale to przydatne informacje
vol7ron
To rozwiązanie IMO jest bardzo dobre. Przydatny efekt uboczny - w łatwy sposób możesz wielokrotnie przywołać przygotowaną wypowiedź.
Yuri
14

W psql istnieje mechanizm poprzez

\set name val

polecenie, które ma być powiązane z -v name=valopcją wiersza poleceń. Cytowanie jest bolesne, w większości przypadków łatwiej jest umieścić całe zapytanie wewnątrz skorupy dokumentu.

Edytować

Ups, powinienem był powiedzieć -vzamiast -P(co jest dla opcji formatowania) poprzednia odpowiedź dobrze.

wildplasser
źródło
7

Parametry można również przekazać w wierszu poleceń psql lub z pliku wsadowego. Pierwsze instrukcje zawierają informacje niezbędne do połączenia się z bazą danych.

Ostatnia zachęta wymaga podania wartości ograniczenia, które zostaną użyte w klauzuli WHERE column IN (). Pamiętaj o umieszczaniu pojedynczych cudzysłowów w ciągach znaków i oddzielaniu ich przecinkami:

@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

Teraz w pliku kodu SQL dodaj token v1 w klauzuli WHERE lub w dowolnym innym miejscu w SQL. Zwróć uwagę, że tokenów można również używać w otwartej instrukcji SQL, a nie tylko w pliku. Zapisz to jako test.sql:

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

W systemie Windows zapisz cały plik jako plik DOS BATch (.bat), zapisz test.sql w tym samym katalogu i uruchom plik wsadowy.

Dziękujemy za Dave Page z EnterpriseDB za oryginalny skrypt podpowiedzi.

MAbraham1
źródło
+1 dla przykładu Windows; chociaż większość baz danych Pg istnieje w wariancie * nix
vol7ron
2

Wydawałoby się, że to, o co prosisz, nie może być wykonane bezpośrednio z wiersza poleceń . Będziesz musiał albo użyć funkcji zdefiniowanej przez użytkownika w plpgsql, albo wywołać zapytanie z języka skryptowego (a to drugie podejście ułatwia uniknięcie wstrzykiwania SQL).

Społeczność
źródło
To nie ja - wielokrotnie chciałbym, aby głosy przeciwne wymagały jakiegoś wyjaśnienia (podobnie jak powody, dla których głosujemy za zamykającymi pytaniami), nawet jeśli pozostawiono je anonimowo.
vol7ron
0

Chciałbym udzielić innej odpowiedzi zainspirowanej komentarzem @ malcook (używając basha).

Ta opcja może zadziałać, jeśli musisz użyć zmiennych powłoki w zapytaniu, gdy używasz -cflagi . W szczególności chciałem uzyskać liczbę tabeli, której nazwa była zmienną powłoki (której nie można przekazać bezpośrednio podczas używania -c).

Załóżmy, że masz zmienną powłoki

$TABLE_NAME='users'

Następnie możesz uzyskać wyniki za pomocą

psql -q -A -t -d databasename -c <<< echo "select count(*) from $TABLE_NAME;"

( -q -A -tsłuży tylko do wydrukowania wynikowej liczby bez dodatkowego formatowania)

Zwrócę uwagę, że echow tu-string ( <<<operator) może nie być konieczne, początkowo myślałem, że cudzysłowy same w sobie będą w porządku, może ktoś może wyjaśnić przyczynę.

Broper
źródło
0

Skończyło się na korzystaniu z lepszej wersji @ vol7ron answer:

DO $$
BEGIN
    IF NOT EXISTS(SELECT 1 FROM pg_prepared_statements WHERE name = 'foo') THEN
        PREPARE foo(text,text,text) AS
            SELECT  * 
            FROM    foobar
            WHERE   foo = $1
                AND bar = $2
                OR  baz = $3;
    END IF;
END$$;
EXECUTE foo('foo','bar','baz');

W ten sposób zawsze możesz wykonać to w takiej kolejności (zapytanie przygotowane tylko jeśli nie zostało jeszcze przygotowane), powtórzyć wykonanie i uzyskać wynik z ostatniego zapytania.

Konard
źródło