psql에서 스크립트 변수를 어떻게 사용합니까?


133

MS SQL Server에서 사용자 정의 변수를 사용하는 스크립트를 작성합니다.

DECLARE @somevariable int  
SELECT @somevariable = -1

INSERT INTO foo VALUES ( @somevariable )

그런 다음 @somevariable특정 상황에서 원하는 값에 따라 런타임시 값을 변경합니다 . 스크립트 상단에 있기 때문에보고 기억하기 쉽습니다.

PostgreSQL 클라이언트와 동일한 작업을 수행하려면 어떻게합니까 psql?


5
FWIW에서 \ set 연산자 는 pgsql 배치 언어가 아니라 psql 명령 줄 도구와 관련된 것으로 보입니다 . 내가 틀렸을 수도있다.
Daniel Yankowsky

1
현재 어떤 Postgres 버전을 사용하고 있습니까?
Kuberchaun

답변:


180

Postgres 변수는 \ set 명령을 통해 생성됩니다 (예 : ...

\set myvariable value

... 예를 들어 다음과 같이 대체 할 수 있습니다.

SELECT * FROM :myvariable.table1;

... 또는 ...

SELECT * FROM table1 WHERE :myvariable IS NULL;

편집 : 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;

66
\setpsql도구 전용 이므로 저장 프로 시저에서 사용할 수 없습니다!
sorin

6
@SorinSbarnea OP는 절차가 아니라 스크립트 에 대해 물었다
Daniel Serodio

35
이 답변은 psql메타 명령 \set과 PostgreSQL 명령을 혼동하는 방식으로 혼합 합니다 .
Erwin Brandstetter

20
postgresql 9.1부터 psql에서 : 'variable'을 사용하여 값으로 올바르게 인용하거나 : variable "을 식별자로 사용할 수 있습니다.
HitScan

9
\set myvariable 'value'이 답변의 말과 달리 변수 안에 따옴표를 포함 하지 않습니다 . 의심 \echo :myvariable스러운 경우 psql 내 에서 사용 하여 임의의 쿼리 값을 독립적으로 표시하십시오.
Daniel Vérité

61

PSQL 변수에 대한 마지막 단어 :

  1. SQL 문에서 작은 따옴표로 묶으면 확장되지 않습니다. 따라서 이것은 작동하지 않습니다.

    SELECT * FROM foo WHERE bar = ':myvariable'
  2. SQL 문에서 문자열 리터럴로 확장하려면 변수 세트에 따옴표를 포함시켜야합니다. 그러나 변수 값은 이미 따옴표로 묶어야합니다. 즉, 두 번째 따옴표 세트가 필요 하고 내부 세트를 이스케이프해야합니다. 따라서 다음이 필요합니다.

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

    편집 : PostgreSQL 9.1부터 다음과 같이 작성할 수 있습니다.

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

12
건배:'myvariable'
Andomar

정확히 내가 찾던 것!
KeniSteward

47

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;

이 방법은 쿼리에서 동일한 계산 값을 몇 번 사용할 때 주로 편리합니다.
skaurus

2
브라이스의 보고서와 달리, 그것은 나에게 잘 작동하는 것 같습니다. 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; 예상대로 잭 잭과 잭의 나이.
Joshua

2
많은 용도, 특히 Python Flask와 같은 웹 응용 프로그램 프레임 워크의 맥락에서 이것은 단일 쿼리 내에서 복잡한 계산 된 값을 재사용하기위한 최상의 솔루션입니다.

1
누구나 이것이 인서트에서 어떻게 작동하는지 제안 할 수 있습니까?
Stoopkid

@Stoopkidcreate table t(x integer); insert into t(x) with sub as (select 999 as num) select num from sub; select * from t;
JL_SO

33

특히 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'을 변경 하고 사용 하는 값 을 사용 하고 기대 하는 함수를 정의 할 수 없습니다 . 함수가 정의되면 한 번 대체되고 그 후에 상수가됩니다. 스크립팅에는 유용하지만 런타임에는 사용하지 않습니다.


psql 변수 (예 : : 'filepath')는 다음과 같이 지적했습니다. "콜론은 인용 부호가없고, 변수 이름 자체는 인용됩니다." 감사! 당신! 나는 이미이 일을하려고하는 이마 모양의 움푹 들어간 곳을 책상에 넣었고, 당신은 나를 더 많이 저장했습니다. 정확히 일부 스크립팅에 필요한 것입니다.
Jason

13

FWIW, 진짜 문제는 \ set 명령 끝에 세미콜론을 포함 시켰다는 것입니다.

\ set owner_password 'thepassword';

세미콜론은 변수에서 실제 문자로 해석되었습니다.

\ echo : owner_password thepassword;

그래서 그것을 사용하려고했을 때 :

역할 미롤 생성 로그인 암호 : owner_password 아니요 CREATEDB CREATEROLE이 유효 할 때까지 '무한대';

...알 겠어:

역할 myrole 작성 암호화되지 않은 비밀번호 thepassword; '무한대'가 될 때까지 CREATEDB CREATEROLE이 유효하지 않습니다.

이것은 리터럴 주위에 따옴표를 설정하는 데 실패했을뿐만 아니라 명령을 2 부분으로 나누었습니다 (두 번째 부분은 "NOINHERIT"로 시작하여 유효하지 않습니다).

이 이야기의 교훈 : PostgreSQL "변수"는 실제 값이 아니라 텍스트 확장에 사용되는 매크로입니다. 나는 그것이 유용하다고 확신하지만 처음에는 까다 롭습니다.


12

SQL proc 언어가 아닌 PL / pgSQL과 같은 절차 적 언어 중 하나를 사용해야합니다. PL / pgSQL에서는 SQL 문에서 바로 vars를 사용할 수 있습니다. 작은 따옴표의 경우 따옴표 리터럴 함수를 사용할 수 있습니다.


5
postgres 자체에서는 수행 할 수 없지만 PSQL 클라이언트 응용 프로그램에서는 수행 할 수 있습니다.
Philluminati

1
plpgsql은 (현재) postgres에서 사용할 수 있습니다 (버전 9.0부터) postgresql.org/docs/9.0/static/sql-do.html
Jasen

11

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 삽입을 완벽하게 보호 할 수 없습니다.


5

다른 접근법은 PostgreSQL GUC 메커니즘을 사용하여 변수를 만드는 것입니다. 이 사전 답변을 참조하십시오 내용과 예는 을 .

에서 GUC를 선언 한 postgresql.conf다음 런타임시 SET명령 을 사용하여 값을 변경하고current_setting(...) .

나는 이것을 일반적인 용도로 권장하지 않지만 포스터가 응용 프로그램 수준의 사용자 이름을 트리거 및 기능에 제공하는 방법을 원했던 링크 된 질문에서 언급 한 것과 같은 좁은 경우에 유용 할 수 있습니다.


4

임시 테이블로 해결했습니다.

CREATE TEMP TABLE temp_session_variables (
    "sessionSalt" TEXT
);
INSERT INTO temp_session_variables ("sessionSalt") VALUES (current_timestamp || RANDOM()::TEXT);

이런 식으로 세션마다 고유 한 여러 쿼리에 대해 사용할 수있는 "변수"를 가졌습니다. 동일한 사용자 이름을 가진 사용자를 가져올 경우 충돌이 발생하지 않으면 서 고유 한 "사용자 이름"을 생성해야했습니다.


이것은 Heidi SQL과 같은 시각적 도구에서 유일하게 작동하는 것으로 보입니다.
Altair7852

2

나는이 질문과 대답이 매우 유용하지만 혼란 스럽다는 것을 알았습니다. 인용 된 변수를 작동시키는 데 많은 어려움이 있었으므로 다음과 같이 작동합니다.

\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';
Jasen

\ set은 SQL이 아닙니다. psql 내장 명령입니다. sql 주석은 지원되지 않습니다.
Jasen

2

나는 그 기능을 정말로 그리워한다. 비슷한 것을 달성하는 유일한 방법은 기능을 사용하는 것입니다.

나는 두 가지 방법으로 그것을 사용했다 :

  • $ _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 = $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';

노트:

  • plperlu는 perl보다 빠릅니다.
  • pg_backend_pid는 최상의 세션 식별이 아닙니다. pg_stat_activity의 backend_start와 pid를 함께 사용하는 것을 고려하십시오.
  • 이 테이블 버전은 때때로 이것이 일어나고 있음을 분명히해야하기 때문에 나쁘다 (현재 작동하는 세션 변수를 삭제하지 않아야 함)

1

의 변수 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)

WTF입니까? 그것은이 아니라 정수 , 그것은의 문자열 999; !

thedatabase=# select 999;
 ?column? 
----------
      999
(1 row)

5
세미콜론이 예기치 않은 일을하는 이유는 세미콜론이 SQL 문을 종료하지만 SQL이 아니고 종료 세미콜론을 사용하지 않는 psql 명령 \ set을 입력하기 때문입니다. 다음 줄에 세미콜론을 넣으면 아프지 않지만 절대 아무것도하지 않습니다. 빈 문장입니다.
volkerk

1

나는 이것 대한 새로운 해결책을 다른 스레드에 게시했습니다 .

테이블을 사용하여 변수를 저장하며 언제든지 업데이트 할 수 있습니다. 정적 불변의 게터 함수는 테이블에 대한 업데이트에 의해 트리거되는 다른 함수에 의해 동적으로 생성됩니다. 멋진 테이블 스토리지와 불변의 게터의 빠른 속도를 얻을 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.