Как вы используете переменные скрипта в psql?
В MS SQL Server я создаю свои скрипты для использования настраиваемых переменных:
DECLARE @somevariable int
SELECT @somevariable = -1
INSERT INTO foo VALUES ( @somevariable )
затем я изменю значение @somevariable во время выполнения, в зависимости от значения, что я хочу в конкретной ситуации. Поскольку он находится в верхней части сценария, его легко увидеть и запомнить.
как я могу сделать то же самое с клиентом PostgreSQL psql?
11 ответов:
переменные Postgres создаются, например, с помощью команды \set ...
\set myvariable value... а потом можно заменить, например, как ...
SELECT * FROM :myvariable.table1;... или. ..
SELECT * FROM table1 WHERE :myvariable IS NULL;... но, если вы хотите использовать переменную в качестве значения в условной строке запроса, например ...
SELECT * FROM table1 WHERE column1 = ':myvariable';... затем вам нужно включить кавычки в саму переменную, так как вышеизложенное не будет работать. Вместо этого определите свою переменную как таковую ...
\set myvariable 'value'однако, если, как и я, вы столкнулись с ситуацией, в которой вы хотели сделать строку из существующей переменной, я нашел трюк, чтобы быть этим ...
\set quoted_myvariable '\'' :myvariable '\''теперь у вас есть как в кавычках, так и без кавычек переменной одной и той же строки! И вы можете сделать нечто подобное ....
INSERT INTO :myvariable.table1 SELECT * FROM table2 WHERE column1 = :quoted_myvariable;
последнее слово о переменных PSQL:
они не расширяются, если вы заключаете их в одинарные кавычки в инструкции SQL. Таким образом это не работает:
SELECT * FROM foo WHERE bar = ':myvariable'чтобы развернуть строковый литерал в инструкции SQL, необходимо включить кавычки в набор переменных. Однако значение переменной уже должно быть заключено в кавычки, что означает, что вам нужно второй набор кавычек, и внутренний набор должен быть экранирован. Таким образом, вам нужно:
\set myvariable '\'somestring\'' SELECT * FROM foo WHERE bar = :myvariableEDIT: начиная с PostgreSQL 9.1, вы можете написать вместо этого:
\set myvariable somestring SELECT * FROM foo WHERE bar = :'myvariable'
вы можете попробовать использовать С предложения.
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;
специально для
psql, вы можете пройтиpsqlпеременные из командной строки тоже; вы можете передать их с-v. Вот пример использования:$ psql -v filepath=/path/to/my/directory/mydatafile.data regress regress=> SELECT :'filepath'; ?column? --------------------------------------- /path/to/my/directory/mydatafile.data (1 row)обратите внимание, что двоеточие не в кавычках, то имя переменной его само в кавычках. Странный синтаксис, я знаю. Это работает только в psql; он не будет работать в (скажем) PgAdmin-III.
эта подстановка происходит во время обработки ввода в psql, поэтому вы не можете (скажем) определить функцию, которая использует
:'filepath'и ожидать значение:'filepath'для перехода от сеанса к сеансу. Он будет заменен один раз, когда функция определена, а затем будет константой после этого. Это полезно для сценариев, но не для использования во время выполнения.
FWIW, реальная проблема заключалась в том, что я включил точку с запятой в конце моей команды \set:
\set owner_password 'thepassword';
точка с запятой интерпретируется как символ в переменной:
\echo :owner_password пароль;
поэтому, когда я попытался использовать его:
создать роль myrole логин незашифрованный пароль: owner_password NOINHERIT CREATEDB CREATEROLE Действует до 'бесконечности';
...Я получил это:
создать роль myrole логин незашифрованный пароль thepassword; NOINHERIT CREATEDB CREATEROLE действителен до 'бесконечности';
что не только не удалось установить кавычки вокруг литерала, но и разделить команду на 2 части (вторая из которых была недействительной, поскольку она начиналась с "NOINHERIT").
мораль этой истории: PostgreSQL "переменные" - это действительно макросы, используемые в тексте расширение, а не истинные значения. Я уверен, что это пригодится, но сначала это сложно.
вам нужно использовать один из процедурных языков, таких как PL/pgSQL, а не язык SQL proc. В PL / pgSQL вы можете использовать vars прямо в SQL-операторах. Для одинарных кавычек можно использовать функцию quote literal.
postgres (начиная с Версии 9.0) позволяет анонимные блоки в любом из поддерживаемых языков сценариев на стороне сервера
DO ' DECLARE somevariable int = -1; BEGIN INSERT INTO foo VALUES ( somevariable ); END ' ;http://www.postgresql.org/docs/current/static/sql-do.html
поскольку все находится внутри строки, внешние строковые переменные, которые подставляются, должны быть экранированы и дважды заключены в кавычки. Использование долларовых котировок вместо этого не даст полной защиты от SQL-инъекции.
другой подход заключается в (ab)использовании механизма PostgreSQL GUC для создания переменных. Смотрите это до ответа для деталей и примеров.
вы объявляете GUC в
postgresql.conf, затем измените его значение во время выполнения сSETкоманды и получить его значение с помощьюcurrent_setting(...).Я не рекомендую это для общего использования, но это может быть полезно в узких случаях, таких как тот, который упоминается в связанном вопросе, где плакат хотел способ обеспечить имя пользователя на уровне приложения для триггеров и функций.
Я решил это с помощью временной таблицы.
CREATE TEMP TABLE temp_session_variables ( "sessionSalt" TEXT ); INSERT INTO temp_session_variables ("sessionSalt") VALUES (current_timestamp || RANDOM()::TEXT);таким образом, у меня была "переменная", которую я мог использовать по нескольким запросам, что является уникальным для сеанса. Мне нужно было создать уникальные "имена пользователей", все еще не имея конфликтов при импорте пользователей с тем же именем пользователя.
Я нашел этот вопрос и ответы очень полезны, но и запутанной. У меня было много проблем с получением цитируемых переменных для работы, так что вот как я это сделал:
\set deployment_user username -- username \set deployment_pass '\'string_password\'' ALTER USER :deployment_user WITH PASSWORD :deployment_pass;таким образом, вы можете определить переменную в одном заявлении. Когда вы используете его, одинарные кавычки будут встроены в переменную.
внимание! Когда я помещаю комментарий после цитируемой переменной, он засасывается как часть переменной, когда я пробовал некоторые методы в других ответах. На какое-то время это меня очень расстроило. С помощью этого метода комментарии, похоже, обрабатываются так, как вы ожидали.
Я очень скучаю по этой функции. Единственный способ добиться чего-то подобного-это использовать функции.
я использовал его двумя способами:
- функции perl, которые используют переменную $_SHARED
- хранить переменные в таблице
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;столе вариант:
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 = ; INSERT INTO var (sess, key, val) VALUES (sessid(), , ::varchar); $$ LANGUAGE 'sql'; CREATE FUNCTION var(varname varchar) RETURNS varchar AS $$ SELECT val FROM var WHERE sess = pg_backend_pid() AND key = ; $$ LANGUAGE 'sql';Примечания:
- plperlu быстрее, чем perl
- pg_backend_pid-это не лучшая идентификация сеанса, рассмотрите возможность использования pid в сочетании с backend_start из pg_stat_activity
- эта версия таблицы также плоха, потому что вы должны очистить это время от времени (и не удалять текущие рабочие переменные сеанса)
Comments