Psql'de betik değişkenlerini nasıl kullanıyorsunuz?


134

MS SQL Server'da, özelleştirilebilir değişkenleri kullanmak için komut dosyalarımı oluşturuyorum:

DECLARE @somevariable int  
SELECT @somevariable = -1

INSERT INTO foo VALUES ( @somevariable )

Daha sonra @somevariable, belirli durumda istediğim değere bağlı olarak çalışma zamanında değerini değiştireceğim . Senaryonun en üstünde olduğu için görmek ve hatırlamak kolaydır.

Aynı şeyi PostgreSQL istemcisiyle nasıl yaparım psql?


5
FWIW, \ set operatörü pgsql toplu iş diliyle değil, psql komut satırı aracıyla ilişkili görünüyor . Yanlış olabilirim.
Daniel Yankowsky

1
Postgres'in hangi sürümünü kullanıyorsunuz?
Kuberchaun

Yanıtlar:


181

Postgres değişkenleri \ set komutu ile oluşturulur, örneğin ...

\set myvariable value

... ve daha sonra örneğin şu şekilde değiştirilebilir ...

SELECT * FROM :myvariable.table1;

... veya ...

SELECT * FROM table1 WHERE :myvariable IS NULL;

düzenleme: psql 9.1'den itibaren, değişkenler aşağıdaki gibi tırnak içinde genişletilebilir:

\set myvariable value 

SELECT * FROM table1 WHERE column1 = :'myvariable';

Psql istemcisinin eski sürümlerinde:

... Değişkeni koşullu bir dize sorgusunda değer olarak kullanmak istiyorsanız, örneğin ...

SELECT * FROM table1 WHERE column1 = ':myvariable';

... o zaman yukarıdaki çalışmayacağından, değişkenin kendisine tırnak işaretlerini eklemeniz gerekir. Bunun yerine değişkeninizi böyle tanımlayın ...

\set myvariable 'value'

Ancak, benim gibi, mevcut bir değişkenden bir dizge yapmak istediğiniz bir durumla karşılaştıysanız, püf noktasını bu buldum ...

\set quoted_myvariable '\'' :myvariable '\''

Artık aynı dizenin hem tırnaklı hem de tırnaksız değişkenine sahipsiniz! Ve bunun gibi bir şey yapabilirsiniz ...

INSERT INTO :myvariable.table1 SELECT * FROM table2 WHERE column1 = :quoted_myvariable;

67
\setsadece psqlalet içindir, onu saklı prosedürlerde kullanamazsınız!
sorin

6
@SorinSbarnea OP prosedürü değil, senaryoyu sordu
Daniel Serodio

35
Bu cevap , kafa karıştırıcı bir şekilde psqlmeta komutları \setPostgreSQL komutlarıyla karıştırır.
Erwin Brandstetter

20
Postgresql 9.1'den itibaren, psql'de artık onu sizin için bir değer olarak uygun şekilde alıntı yapmak için 'değişken' veya bir tanımlayıcı olarak kullanmak için: 'değişken' kullanabilirsiniz.
HitScan

9
\set myvariable 'value'yok değil bu cevabı ne diyor aksine değişken içindeki herhangi alıntı içerir. Şüpheye düştüğünüzde, \echo :myvariabledeğeri herhangi bir sorgudan bağımsız olarak görüntülemek için psql içinde kullanın.
Daniel Vérité

61

PSQL değişkenleri hakkında son bir söz:

  1. SQL deyiminde tek tırnak içine alırsanız genişlemezler. Dolayısıyla bu işe yaramıyor:

    SELECT * FROM foo WHERE bar = ':myvariable'
  2. Bir SQL deyiminde bir dizgeye genişletmek için, değişken kümesine tırnak işaretlerini dahil etmeniz gerekir. Bununla birlikte, değişken değerin zaten tırnak içine alınması gerekir, bu da ikinci bir tırnak setine ihtiyacınız olduğu ve iç kümeden çıkış yapılması gerektiği anlamına gelir . Bu nedenle ihtiyacınız olan:

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

    DÜZENLEME : PostgreSQL 9.1 ile başlayarak, bunun yerine yazabilirsiniz:

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

12
Şerefe:'myvariable'
Andomar

Tam olarak aradığım şey!
KeniSteward

47

Bir WITH cümlesi kullanmayı deneyebilirsiniz .

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;

Bu yöntem, sorgunuzda aynı hesaplanmış değerleri birkaç kez kullandığınızda çoğunlukla kullanışlıdır.
skaurus

2
Bryce'ın raporunun aksine, benim için iyi çalışıyor gibi görünüyor. 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; Jack ve Jack'in yaşı, beklendiği gibi çıktı.
Joshua

2
Pek çok kullanım için, özellikle Python Flask gibi bir web uygulaması çerçevesi bağlamında, bu, karmaşık hesaplanmış değerleri tek bir sorgu içinde yeniden kullanmak için en iyi çözümdür.
Will

1
Bunun bir ekte nasıl çalışacağını kimse önerebilir mi?
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

Özellikle psql, psqldeğişkenleri komut satırından da aktarabilirsiniz ; onlarla geçebilirsiniz -v. İşte bir kullanım örneği:

$ psql -v filepath=/path/to/my/directory/mydatafile.data regress
regress=> SELECT :'filepath';
               ?column?                
---------------------------------------
 /path/to/my/directory/mydatafile.data
(1 row)

İki nokta üst üste işaretinin tırnaksız olduğuna, daha sonra değişken adının kendinden alıntı yapıldığına dikkat edin. Garip sözdizimi, biliyorum. Bu yalnızca psql'de çalışır; PgAdmin-III'te çalışmayacaktır.

Bu değiştirme psql'de girdi işleme sırasında gerçekleşir, bu nedenle :'filepath'değerinin :'filepath'oturumdan oturuma değişmesini bekleyen ve kullanan bir işlev tanımlayamazsınız (diyemezsiniz) . İşlev tanımlandığında bir kez değiştirilecek ve bundan sonra sabit olacaktır. Komut dosyası oluşturmak için kullanışlıdır, ancak çalışma zamanı kullanımı için uygun değildir.


psql değişkenleri, örneğin: 'dosya yolu', şunu belirttiniz: "İki nokta üst üste işaretinin tırnaksız olduğuna dikkat edin, daha sonra değişken adı kendinden alıntılanır." Teşekkür! Sen! Bu işi yapmak için masama bir sürü alın şeklindeki oyuk yerleştirdim ve sen beni bir ton daha kurtardın. Bazı komut dosyaları için tam da ihtiyacım olan şey.
Jason

13

FWIW, asıl sorun, \ set komutumun sonuna bir noktalı virgül eklemiş olmamdı:

\ owner_password 'şifreyi' ayarlayın;

Noktalı virgül, değişkende gerçek bir karakter olarak yorumlandı:

\ echo: owner_password parola;

Bu yüzden kullanmaya çalıştığımda:

ROL OLUŞTUR myrole GİRİŞ SİPARİŞ EDİLMEMİŞ ŞİFRE: owner_password NOINHERIT CREATEROLE 'sonsuza' KADAR GEÇERLİDİR;

...Bunu anladım:

ROL OLUŞTUR myrole GİRİŞ SİPARİŞ EDİLMEMİŞ ŞİFRE; NOINHERIT CREATEDB CREATEROLE 'sonsuza' KADAR GEÇERLİDİR;

Bu sadece tırnak işaretlerini değişmezin etrafında ayarlamakta başarısız olmakla kalmadı, aynı zamanda komutu 2 parçaya böldü (ikincisi "NOINHERIT" ile başladığı için geçersizdi).

Bu hikayenin ahlaki: PostgreSQL "değişkenleri" gerçekten metin yorumlamasında kullanılan makrolardır, gerçek değerler değil. Eminim işe yarayacaktır, ama ilk başta zor.


12

SQL proc dili değil PL / pgSQL gibi prosedürel dillerden birini kullanmanız gerekir. PL / pgSQL'de, SQL deyimlerinde varsayı kullanabilirsiniz. Tek tırnak için tırnak değişmez işlevini kullanabilirsiniz.


5
Postgres'te yapılamaz, ancak PSQL istemci uygulamasında yapılabilir.
Philluminati

1
plpgsql (şimdi) postgres'de kullanılabilir (sürüm 9.0'dan beri)) postgresql.org/docs/9.0/static/sql-do.html
Jasen

11

postgres (sürüm 9.0'dan beri), desteklenen sunucu tarafı kodlama dillerinin herhangi birinde anonim engellemelere izin verir

DO '
DECLARE somevariable int = -1;
BEGIN
INSERT INTO foo VALUES ( somevariable );
END
' ;

http://www.postgresql.org/docs/current/static/sql-do.html

Her şey bir dizgenin içinde olduğundan, ikame edilen harici dize değişkenlerinin iki kez öncelenmesi ve alıntılanması gerekecektir. Bunun yerine dolar alıntı kullanmak SQL enjeksiyonuna karşı tam koruma sağlamayacaktır.


5

Diğer bir yaklaşım, değişkenler oluşturmak için (ab) PostgreSQL GUC mekanizmasını kullanmaktır. Bu önceki cevaba bakınAyrıntılar ve örnekler için .

GUC'yi içinde bildirirsiniz postgresql.conf, ardından çalışma zamanında değerini SETkomutlarla değiştirir ve değerini alırsınız.current_setting(...) .

Bunu genel kullanım için önermiyorum, ancak bağlantılı soruda belirtilen gibi, gönderenin tetikleyicilere ve işlevlere uygulama düzeyinde kullanıcı adı sağlamanın bir yolunu istediği dar durumlarda yararlı olabilir.


4

Geçici bir tablo ile çözdüm.

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

Bu şekilde, oturum için benzersiz olan birden çok sorgularda kullanabileceğim bir "değişken" elde ettim. Aynı kullanıcı adına sahip kullanıcıları içe aktarırken yine de çarpışmalar yaşamadan benzersiz "kullanıcı adları" oluşturması için buna ihtiyacım vardı.


Bu, Heidi SQL gibi görsel araçlarda çalışan tek yol gibi görünüyor.
Altair7852

2

Bu soruyu ve cevapları son derece yararlı buldum, ama aynı zamanda kafa karıştırıcı. Alıntılanan değişkenleri çalıştırmak için çok fazla sorun yaşadım, işte onu çalıştırma şeklim:

\set deployment_user username    -- username
\set deployment_pass '\'string_password\''
ALTER USER :deployment_user WITH PASSWORD :deployment_pass;

Bu şekilde değişkeni tek bir ifadede tanımlayabilirsiniz. Bunu kullandığınızda, değişkene tek tırnak işaretleri yerleştirilecektir.

NOT! Alıntılanan değişkenden sonra bir yorum yazdığımda, diğer cevaplardaki yöntemlerden bazılarını denediğimde değişkenin bir parçası olarak emildi. Bu beni bir süreliğine alt üst etti. Bu yöntemle yorumlar beklediğiniz gibi değerlendirilir.


\set deployment_pass 'string_password' ALTER USER :deployment_user WITH PASSWORD :'deployment_pass';
Jasen

\ set SQL değil, yerleşik bir psql komutu. sql açıklamaları desteklenmiyor.
Jasen

2

Bu özelliği gerçekten özledim. Benzer bir şey elde etmenin tek yolu işlevleri kullanmaktır.

Bunu iki şekilde kullandım:

  • $ _SHARED değişkenini kullanan perl işlevleri
  • değişkenlerinizi tabloda saklayın

Perl versiyonu:

   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;

Tablo versiyonu:

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

Notlar:

  • plperlu perl'den daha hızlıdır
  • pg_backend_pid en iyi oturum tanımlama değildir, pid ile birlikte pg_stat_activity'den arka uç_başlangıç ​​kullanmayı düşünün
  • bu tablo sürümü de kötüdür çünkü ara sıra bu durumu temizlemeniz gerekir (ve şu anda çalışan oturum değişkenlerini silmemek)

1

Değişkenler psql . Bir tamsayı bildirmek istiyorsanız, tamsayı girmeniz, ardından bir satırbaşı yapmanız ve ardından ifadeyi noktalı virgülle sonlandırmanız gerekir. Gözlemek:

Diyelim ki bir tamsayı değişkeni my_vartanımlayıp bir tabloya eklemek istiyorum test:

Örnek tablo 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)

Açıkça, bu tabloda henüz hiçbir şey yok:

thedatabase=# select * from test;
 id 
----
(0 rows)

Bir değişken tanımlıyoruz. Bir sonraki satırda noktalı virgülün nasıl olduğuna dikkat edin!

thedatabase=# \set my_var 999
thedatabase=# ;

Şimdi ekleyebiliriz. Bu tuhaf :''görünümlü sözdizimini " " kullanmalıyız :

thedatabase=# insert into test(id) values (:'my_var');
INSERT 0 1

İşe yaradı!

thedatabase=# select * from test;
 id  
-----
 999
(1 row)

Açıklama:

Öyleyse ... sonraki satırda noktalı virgül yoksa ne olur? Değişken? Bir göz atın:

my_varYeni hat olmadan beyan ederiz .

thedatabase=# \set my_var 999;

Seçelim my_var.

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

Bu ne lan? Tamsayı değil , dizge 999; !

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

5
Noktalı virgülün sizin için beklenmedik şeyler yapmasının nedeni, noktalı virgülün bir SQL ifadesini sonlandırmasıdır, ancak siz bir psql komutu yazıyorsunuz, \ set, SQL olmayan ve sonlandırıcı bir noktalı virgül ALMAYIN. Sonraki satıra noktalı virgül koymak zarar vermez, ancak kesinlikle hiçbir şey yapmaz. Bu boş bir ifade.
volkerk

1

Bunun için başka bir ileti dizisinde yeni bir çözüm yayınladım .

Değişkenleri saklamak için bir tablo kullanır ve herhangi bir zamanda güncellenebilir. Statik, değişmez bir alıcı işlevi, (başka bir işlev tarafından) dinamik olarak oluşturulur ve tablonuzun güncellenmesiyle tetiklenir. Güzel bir masa depolama alanına ve ayrıca sabit bir toplayıcının çarpıcı hızlarına sahip oluyorsunuz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.