W MS SQL Server tworzę swoje skrypty do używania zmiennych konfigurowalnych:
DECLARE @somevariable int
SELECT @somevariable = -1
INSERT INTO foo VALUES ( @somevariable )
Następnie zmienię wartość @somevariable
w czasie wykonywania, w zależności od wartości, której chcę w konkretnej sytuacji. Ponieważ znajduje się na górze skryptu, jest łatwy do zobaczenia i zapamiętania.
Jak mam zrobić to samo z klientem PostgreSQL psql
?
sql
postgresql
variables
psql
Craig Walker
źródło
źródło
Odpowiedzi:
Zmienne Postgres są tworzone za pomocą polecenia \ set, na przykład ...
\set myvariable value
... i można go następnie zastąpić, na przykład, jako ...
SELECT * FROM :myvariable.table1;
... lub ...
SELECT * FROM table1 WHERE :myvariable IS NULL;
edycja: Od wersji psql 9.1 zmienne można interpretować w cudzysłowach, jak w:
\set myvariable value SELECT * FROM table1 WHERE column1 = :'myvariable';
W starszych wersjach klienta psql:
... Jeśli chcesz użyć zmiennej jako wartości w warunkowym zapytaniu łańcuchowym, takim jak ...
SELECT * FROM table1 WHERE column1 = ':myvariable';
... wtedy musisz zawrzeć cudzysłowy w samej zmiennej, ponieważ powyższe nie zadziała. Zamiast tego zdefiniuj zmienną jako taką ...
\set myvariable 'value'
Jeśli jednak, tak jak ja, napotkasz sytuację, w której chciałeś utworzyć ciąg z istniejącej zmiennej, znalazłem trik w tym ...
\set quoted_myvariable '\'' :myvariable '\''
Teraz masz zmienną w cudzysłowie i niecytowaną, składającą się z tego samego ciągu! I możesz zrobić coś takiego ....
INSERT INTO :myvariable.table1 SELECT * FROM table2 WHERE column1 = :quoted_myvariable;
źródło
\set
jest tylko dlapsql
narzędzia, nie można go używać w procedurach składowanych!psql
meta-polecenia\set
z poleceniami PostgreSQL.\set myvariable 'value'
czy nie zawierają żadnych cytatów wewnątrz zmiennej, w przeciwieństwie do tego, co mówi ta odpowiedź. W razie wątpliwości użyj\echo :myvariable
w psql, aby wyświetlić wartość niezależnie od zapytania.Ostatnie słowo na temat zmiennych PSQL:
Nie rozszerzają się, jeśli umieścisz je w pojedynczych cudzysłowach w instrukcji SQL. Zatem to nie działa:
SELECT * FROM foo WHERE bar = ':myvariable'
Aby rozwinąć do literału łańcuchowego w instrukcji SQL, musisz uwzględnić cudzysłowy w zestawie zmiennych. Jednak wartość zmiennej musi już być ujęta w cudzysłów, co oznacza, że potrzebujesz drugiego zestawu cudzysłowów, a wewnętrzny zestaw musi zostać zmieniony. Potrzebujesz więc:
\set myvariable '\'somestring\'' SELECT * FROM foo WHERE bar = :myvariable
EDYCJA : zaczynając od PostgreSQL 9.1, możesz zamiast tego napisać:
\set myvariable somestring SELECT * FROM foo WHERE bar = :'myvariable'
źródło
:'myvariable'
Możesz spróbować użyć klauzuli WITH .
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;
źródło
CREATE TABLE test (name VARCHAR, age INT);
INSERT INTO test (name, age) VALUES ('Jack', 21), ('Jill', 20);
WITH vars AS (SELECT N'Jack' AS name, 21 AS age) SELECT test.* FROM test, vars WHERE test.name = vars.name and test.age = vars.age;
Wiek Ouputs Jack i Jack, zgodnie z oczekiwaniami.create table t(x integer);
insert into t(x) with sub as (select 999 as num) select num from sub;
select * from t;
W szczególności w przypadku
psql
można również przekazywaćpsql
zmienne z wiersza poleceń; możesz je przekazać-v
. Oto przykład użycia:$ psql -v filepath=/path/to/my/directory/mydatafile.data regress regress=> SELECT :'filepath'; ?column? --------------------------------------- /path/to/my/directory/mydatafile.data (1 row)
Zwróć uwagę, że dwukropek nie jest cytowany, a następnie cytowana jest nazwa zmiennej, do której należy ona. Wiem, dziwna składnia. Działa to tylko w psql; nie zadziała w (powiedzmy) PgAdmin-III.
To podstawienie ma miejsce podczas przetwarzania danych wejściowych w psql, więc nie możesz (powiedzmy) zdefiniować funkcji, która używa
:'filepath'
i oczekuje, że wartość:'filepath'
zmieni się z sesji na sesję. Zostanie podstawiony raz, kiedy funkcja zostanie zdefiniowana, a potem będzie stała. Jest to przydatne do tworzenia skryptów, ale nie w czasie wykonywania.źródło
FWIW, prawdziwy problem polegał na tym, że na końcu mojego polecenia \ set umieściłem średnik:
Średnik został zinterpretowany jako rzeczywisty znak w zmiennej:
Więc kiedy próbowałem go użyć:
...Mam to:
To nie tylko nie spowodowało ustawienia cudzysłowów wokół literału, ale podzieliło polecenie na 2 części (z których druga była nieprawidłowa, ponieważ zaczynała się od „NOINHERIT”).
Morał z tej historii: „zmienne” PostgreSQL to tak naprawdę makra używane do interpretacji tekstu, a nie prawdziwe wartości. Jestem pewien, że to się przydaje, ale na początku jest trudne.
źródło
Musisz użyć jednego z języków proceduralnych, takich jak PL / pgSQL, a nie języka SQL proc. W PL / pgSQL możesz używać zmiennych bezpośrednio w instrukcjach SQL. W przypadku pojedynczych cudzysłowów możesz użyć funkcji literału cudzysłowu.
źródło
postgres (od wersji 9.0) pozwala na anonimowe bloki w każdym z obsługiwanych języków skryptów po stronie serwera
DO ' DECLARE somevariable int = -1; BEGIN INSERT INTO foo VALUES ( somevariable ); END ' ;
http://www.postgresql.org/docs/current/static/sql-do.html
Ponieważ wszystko znajduje się wewnątrz łańcucha, zewnętrzne zmienne łańcuchowe, które są podstawiane, będą musiały zostać umieszczone dwukrotnie w cudzysłowie. Użycie zamiast tego cudzysłowu nie zapewni pełnej ochrony przed wstrzyknięciem SQL.
źródło
Innym podejściem jest (ab) użycie mechanizmu PostgreSQL GUC do tworzenia zmiennych. Zobacz tę wcześniejszą odpowiedź, aby uzyskać szczegółowe informacje i przykłady.
Deklarujesz GUC w
postgresql.conf
, a następnie zmieniasz jego wartość w czasie wykonywania za pomocąSET
poleceń i uzyskujesz jego wartość za pomocącurrent_setting(...)
.Nie polecam tego do ogólnego użytku, ale może być przydatne w wąskich przypadkach, takich jak ten wspomniany w powiązanym pytaniu, w którym plakat chciał zapewnić sposób podania nazwy użytkownika na poziomie aplikacji do wyzwalaczy i funkcji.
źródło
Rozwiązałem to za pomocą tabeli tymczasowej.
CREATE TEMP TABLE temp_session_variables ( "sessionSalt" TEXT ); INSERT INTO temp_session_variables ("sessionSalt") VALUES (current_timestamp || RANDOM()::TEXT);
W ten sposób miałem „zmienną”, której mogłem użyć w wielu zapytaniach, która jest unikalna dla sesji. Potrzebowałem go do generowania unikalnych „nazw użytkowników”, jednocześnie nie mając kolizji podczas importowania użytkowników o tej samej nazwie użytkownika.
źródło
Uważam, że to pytanie i odpowiedzi są niezwykle przydatne, ale także zagmatwane. Miałem wiele problemów z uruchomieniem cytowanych zmiennych, więc oto sposób, w jaki je uruchomiłem:
\set deployment_user username -- username \set deployment_pass '\'string_password\'' ALTER USER :deployment_user WITH PASSWORD :deployment_pass;
W ten sposób możesz zdefiniować zmienną w jednej instrukcji. Kiedy go użyjesz, pojedyncze cudzysłowy zostaną osadzone w zmiennej.
UWAGA! Kiedy umieściłem komentarz po cytowanej zmiennej, został on zassany jako część zmiennej, gdy wypróbowałem niektóre metody w innych odpowiedziach. To naprawdę mnie wkurzało przez jakiś czas. Dzięki tej metodzie komentarze wydają się być traktowane zgodnie z oczekiwaniami.
źródło
\set deployment_pass 'string_password'
ALTER USER :deployment_user WITH PASSWORD :'deployment_pass';
Naprawdę tęsknię za tą funkcją. Jedynym sposobem osiągnięcia czegoś podobnego jest użycie funkcji.
Użyłem go na dwa sposoby:
Wersja Perla:
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;
Wersja stołowa:
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';
Uwagi:
źródło
Zmienne w
psql
ssaniu. Jeśli chcesz zadeklarować liczbę całkowitą, musisz wprowadzić tę liczbę, następnie wykonać znak powrotu karetki, a następnie zakończyć instrukcję średnikiem. Przestrzegać:Powiedzmy, że chcę zadeklarować zmienną całkowitą
my_var
i wstawić ją do tabelitest
:Przykładowa tabela
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)
Oczywiście w tej tabeli nie ma jeszcze nic:
thedatabase=# select * from test; id ---- (0 rows)
Deklarujemy zmienną. Zwróć uwagę, że średnik znajduje się w następnej linii!
thedatabase=# \set my_var 999 thedatabase=# ;
Teraz możemy wstawić. Musimy użyć tej dziwnie
:''
wyglądającej " " składni:thedatabase=# insert into test(id) values (:'my_var'); INSERT 0 1
Zadziałało!
thedatabase=# select * from test; id ----- 999 (1 row)
Wyjaśnienie:
Więc ... co się stanie, jeśli w następnym wierszu nie będzie średnika? Zmienna? Spójrz:
Deklarujemy
my_var
bez nowej linii.thedatabase=# \set my_var 999;
Wybierzmy
my_var
.thedatabase=# select :'my_var'; ?column? ---------- 999; (1 row)
Co to do cholery jest? To nie jest liczba całkowita , to ciąg znaków
999;
!thedatabase=# select 999; ?column? ---------- 999 (1 row)
źródło
Opublikowałem nowe rozwiązanie tego problemu w innym wątku .
Używa tabeli do przechowywania zmiennych i może być aktualizowana w dowolnym momencie. Statyczna niezmienna funkcja pobierająca jest tworzona dynamicznie (przez inną funkcję), wyzwalana przez aktualizację tabeli. Otrzymujesz niezłe miejsce do przechowywania, a także niesamowitą prędkość niezmiennego gettera.
źródło