В MS SQL Server я создаю свои скрипты для использования настраиваемых переменных:
DECLARE @somevariable int
SELECT @somevariable = -1
INSERT INTO foo VALUES ( @somevariable )
Затем я изменю значение @somevariable
во время выполнения в зависимости от значения, которое я хочу получить в конкретной ситуации. Так как это вверху сценария, его легко увидеть и запомнить.
Как мне сделать то же самое с клиентом PostgreSQL psql
?
Переменные Postgres создаются с помощью команды \set, например...
\set myvariable value
... и затем может быть заменен, например, как...
SELECT * FROM :myvariable.table1;
... или же...
SELECT * FROM table1 WHERE :myvariable IS NULL;
edit: Начиная с psql 9.1, переменные могут быть расширены в кавычки, как в:
\set myvariable value
SELECT * FROM table1 WHERE column1 = :'myvariable';
В старых версиях клиента psql:
... Если вы хотите использовать переменную в качестве значения в запросе условной строки, например...
SELECT * FROM table1 WHERE column1 = ':myvariable';
... тогда вам нужно включить кавычки в саму переменную, так как выше не будет работать. Вместо этого определите свою переменную как таковую...
\set myvariable 'value'
Однако, если, как и я, вы столкнулись с ситуацией, в которой вы хотели создать строку из существующей переменной, я обнаружил, что хитрость заключается в следующем...
\set quoted_myvariable '\'' :myvariable '\''
Теперь у вас есть как в кавычках, так и в кавычках переменная одной строки! И вы можете сделать что-то вроде этого....
INSERT INTO :myvariable.table1 SELECT * FROM table2 WHERE column1 = :quoted_myvariable;
\set
предназначен только для инструмента psql
, его нельзя использовать в хранимых процедурах!
Последнее слово для переменных PSQL:
Они не расширяются, если вы заключите их в одинарные кавычки в инструкции SQL. Таким образом, это не работает:
SELECT * FROM foo WHERE bar = ':myvariable'
Чтобы перейти к строковому литералу в инструкции SQL, вам нужно включить кавычки в набор переменных. Однако значение переменной уже должно быть заключено в кавычки, а это значит, что вам нужен второй набор кавычек, а внутренний набор должен быть экранирован. Таким образом, вам нужно:
\set myvariable '\'somestring\''
SELECT * FROM foo WHERE bar = :myvariable
РЕДАКТИРОВАТЬ: начиная с PostgreSQL 9.1, вы можете написать вместо этого:
\set myvariable somestring
SELECT * FROM foo WHERE bar = :'myvariable'
:'myvariable'
Вы можете попробовать использовать 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;
WHERE
. справедливое предупреждение.
В частности, для 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)
Обратите внимание, что двоеточие без кавычек, затем указывается имя переменной self. Нечетный синтаксис, я знаю. Это работает только в psql; он не будет работать (скажем) PgAdmin-III.
Эта подстановка происходит во время обработки ввода в psql, поэтому вы не можете (скажем) определить функцию, которая использует :'filepath'
, и ожидать, что значение :'filepath'
изменится с сеанса на сеанс. Он будет заменен один раз, когда функция будет определена, а затем после этого будет константой. Это полезно для сценариев, но не для использования во время выполнения.
Вам нужно использовать один из процедурных языков, таких как PL/pgSQL, а не язык proc proc. В PL/pgSQL вы можете использовать vars прямо в операторах SQL. Для одинарных кавычек вы можете использовать функцию буквенного цитирования.
FWIW, реальная проблема заключалась в том, что я включил точку с запятой в конце моей команды \set:
\ set owner_password 'thepassword';
Точка с запятой была интерпретирована как действительный символ в переменной:
\ echo: owner_password thepassword;
Итак, когда я попытался использовать его:
СОЗДАТЬ РОЛЬ myrole LOGIN UNENCRYPTED PASSWORD: owner_password NOINHERIT CREATEDB CREATEROLE VALID UNTIL 'бесконечность';
... Я получил это:
СОЗДАТЬ РОЛЬ myrole LOGIN UNENCRYPTED PASSWORD thepassword; NOINHERIT CREATEDB CREATEROLE VALID UNTIL 'бесконечность';
Это не только не удалось установить кавычки вокруг литерала, а разделить команду на две части (вторая из которых была недействительной, поскольку она начиналась с "NOINHERIT" ).
Мораль этой истории: "переменные" PostgreSQL - это действительно макросы, используемые в расширении текста, а не истинные значения. Я уверен, что это пригодится, но сначала это сложно.
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-инъекций.
Я решил это с помощью таблицы temp.
CREATE TEMP TABLE temp_session_variables (
"sessionSalt" TEXT
);
INSERT INTO temp_session_variables ("sessionSalt") VALUES (current_timestamp || RANDOM()::TEXT);
Таким образом, у меня была "переменная", которую я мог бы использовать по нескольким запросам, что уникально для сеанса. Мне было нужно, чтобы он генерировал уникальные "имена пользователей", но не имел коллизий при импорте пользователей с тем же именем пользователя.
Другим подходом является (ab) использование механизма PostgreSQL GUC для создания переменных. Подробнее см. этот предварительный ответ.
Вы объявляете GUC в postgresql.conf
, а затем изменяете его значение во время выполнения с помощью команд SET
и получаете его значение с помощью current_setting(...)
.
Я не рекомендую это для общего использования, но он может быть полезен в узких случаях, таких как упомянутый в связанном вопросе, где плакат хотел, чтобы предоставить имя пользователя на уровне приложения для триггеров и функций.
Я очень скучаю по этой функции. Единственный способ добиться чего-то подобного - использовать функции.
Я использовал его двумя способами:
Версия на 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 = $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';
Примечания:
Я нашел этот вопрос, и ответы чрезвычайно полезны, но также запутывают. У меня было много проблем с работой с цитируемыми переменными, поэтому вот как я его работал:
\set deployment_user username -- username
\set deployment_pass '\'string_password\''
ALTER USER :deployment_user WITH PASSWORD :deployment_pass;
Таким образом вы можете определить переменную в одном выражении. Когда вы его используете, одиночные кавычки будут внедрены в переменную.
ВНИМАНИЕ! Когда я помещаю комментарий после цитируемой переменной, он всасывается как часть переменной, когда я пытался использовать некоторые из методов в других ответах. Это на самом деле напугало меня на некоторое время. С этим методом комментарии выглядят так, как вы ожидали.
\set deployment_pass 'string_password'
ALTER USER :deployment_user WITH PASSWORD :'deployment_pass';
\set deployment_pass 'string_password'
ALTER USER :deployment_user WITH PASSWORD :'deployment_pass';
\set deployment_pass 'string_password'
ALTER USER :deployment_user WITH PASSWORD :'deployment_pass';
Я разместил новое решение для этого в другой теме.
Он использует таблицу для хранения переменных и может быть обновлен в любое время. Статическая неизменяемая функция-получатель создается динамически (другой функцией) и запускается обновлением таблицы. Вы получаете отличное хранилище, плюс невероятно высокие скорости неизменного добытчика.
Переменные в psql
отстой. Если вы хотите объявить целое число, вы должны ввести целое число, затем выполнить возврат каретки, а затем завершить оператор точкой с запятой. Заметим:
Допустим, я хочу объявить целочисленную переменную my_var
и вставить ее в test
таблицы:
Пример 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)
Понятно, что ничего в этой таблице пока нет:
thedatabase=# select * from test;
id
----
(0 rows)
Мы объявляем переменную. Обратите внимание на точку с запятой в следующей строке!
thedatabase=# \set my_var 999
thedatabase=# ;
Теперь мы можем вставить. Мы должны использовать этот странный синтаксис " :''
:
thedatabase=# insert into test(id) values (:'my_var');
INSERT 0 1
Это сработало!
thedatabase=# select * from test;
id
-----
999
(1 row)
Объяснение:
Итак... что произойдет, если у нас нет точки с запятой в следующей строке? Переменная? Посмотри:
Мы объявляем my_var
без новой строки.
thedatabase=# \set my_var 999;
Позвольте выбрать my_var
.
thedatabase=# select :'my_var';
?column?
----------
999;
(1 row)
Что это за хрень? Это не целое число, это строка 999;
!
thedatabase=# select 999;
?column?
----------
999
(1 row)