Как вы используете переменные скрипта в psql?



В MS SQL Server я создаю свои скрипты для использования настраиваемых переменных:



DECLARE @somevariable int  
SELECT @somevariable = -1

INSERT INTO foo VALUES ( @somevariable )


затем я изменю значение @somevariable во время выполнения, в зависимости от значения, что я хочу в конкретной ситуации. Поскольку он находится в верхней части сценария, его легко увидеть и запомнить.



как я могу сделать то же самое с клиентом PostgreSQL psql?

2018   11  

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:

  1. они не расширяются, если вы заключаете их в одинарные кавычки в инструкции SQL. Таким образом это не работает:

    SELECT * FROM foo WHERE bar = ':myvariable'
    
  2. чтобы развернуть строковый литерал в инструкции SQL, необходимо включить кавычки в набор переменных. Однако значение переменной уже должно быть заключено в кавычки, что означает, что вам нужно второй набор кавычек, и внутренний набор должен быть экранирован. Таким образом, вам нужно:

    \set myvariable '\'somestring\''  
    SELECT * FROM foo WHERE bar = :myvariable
    

    EDIT: начиная с 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

    Ничего не найдено.