PostgreSQL sorgusunda bir değişken nasıl bildirilir


241

PostgreSQL 8.3 sorgusunda kullanılmak üzere bir değişkeni nasıl bildirebilirim?

MS SQL Server'da bunu yapabilirim:

DECLARE @myvar INT
SET @myvar = 5

SELECT *
FROM somewhere
WHERE something = @myvar

Aynı şeyi PostgreSQL'de nasıl yapabilirim? Belgelere göre değişkenler basitçe "ad tipi" olarak bildirilir, ancak bu bana bir sözdizimi hatası verir:

myvar INTEGER;

Birisi bana doğru sözdizimine bir örnek verebilir mi?


2
Sadece PostgreSQL ile yapılabilir. Bu ilgili sorunun cevabına bakın: stackoverflow.com/questions/766657/…
Sean the Bean

2
Bu yanıtın daha iyi yanıtları var: stackoverflow.com/questions/13316773/…
Erwin Brandstetter

Yanıtlar:


113

PostgreSQL'de böyle bir özellik yoktur. Bunu sadece pl / PgSQL'de (veya başka bir pl / *) yapabilirsiniz, ancak düz SQL'de yapamazsınız.

Bir istisna, WITH ()değişken, hatta değişken olarak çalışabilen sorgudur tuple. Geçici değerler tablosu döndürmenizi sağlar.

WITH master_user AS (
    SELECT
      login,
      registration_date
    FROM users
    WHERE ...
)

SELECT *
FROM users
WHERE master_login = (SELECT login
                      FROM master_user)
      AND (SELECT registration_date
           FROM master_user) > ...;

Bu yöntem CTE'lerin elverişli olarak kullanılmasını denedim. Ancak hızlı bir şekilde, CTE'lerde farklı veri değiştirme sorgularının birbirlerinin etkilerini göreceği garanti edilmeyen bir soruna rastladım. Birden çok sorguda bu değişkeni kullanmak için gerektiği gibi birden çok CTE kullanmak zorunda kaldı.
Zia Ul Rehman Mughal

228

Aynı amacı bir WITHmadde kullanarak başardım , o kadar zarif değil ama aynı şeyi yapabilir. Bu örnek için çok abartılı olmasına rağmen. Ayrıca özellikle bu önermiyoruz.

WITH myconstants (var1, var2) as (
   values (5, 'foo')
)
SELECT *
FROM somewhere, myconstants
WHERE something = var1
   OR something_else = var2;

2
Bu, değişken istediğiniz çoğu örnek için harika çalışır. Bununla birlikte, LIMIT için bir değişken kullanmak istiyorsanız (değişken içeremez), o zaman \setShahriar Aghajani'nin cevabında önerildiği gibi kullanmak istersiniz .
cimmanon

1
Bu, bazı ilişkisel verileri almak istediğim bir geçiş komut dosyasına sahip olduğum zamanlar için idealdir. Açıkçası ben ilişkisel veri verilen dizi kimliği bilmiyorum.
Relequestual

3
Sadece bu yaklaşımı denedim ve belki de daha iyi bir yol buldum: JOIN myconstants ON trueve sonra alt seçimi yapmaya gerek yok.
Vektör

7
Bu yalnızca tek bir sorguda çalışır, WITHCTE'yi bir işlemdeki sorgular arasında paylaşamazsınız .
Daenyth

2
Burada burada Eski soru, ama varyasyonu olan: WITH constants AS (SELECT 5 AS var) SELECT * FROM somewhere CROSS JOIN constants WHERE someting=var;. CROSS JOIN, tek satırlı bir tablo ifadesine sahip olan, gerçek tablodaki tüm satırların verilerini neredeyse çoğaltır ve ifadeyi basitleştirir.
Manngo

83

Bunu PLPGSQL'de de deneyebilirsiniz:

DO $$
DECLARE myvar integer;
BEGIN
    SELECT 5 INTO myvar;

    DROP TABLE IF EXISTS tmp_table;
    CREATE TABLE tmp_table AS
    SELECT * FROM yourtable WHERE   id = myvar;
END $$;

SELECT * FROM tmp_table;

Yukarıdakiler Postgres 9.0 veya üstünü gerektirir.


1
DO deyimi PostgreSQL 9.0'da eklenmiştir ve 8.3'te çalışmaz.
Johny

14
CREATE TABLE ifadesini kullanın. Ama başka türlü iyi.
Stefan Steiger

60

Dinamik Yapılandırma Ayarları

bunun için dinamik yapılandırma ayarlarını "kötüye kullanabilirsiniz":

-- choose some prefix that is unlikely to be used by postgres
set session my.vars.id = '1';

select *
from person 
where id = current_setting('my.vars.id')::int;

Yapılandırma ayarları her zaman varchar değerleridir, bu nedenle bunları kullanırken doğru veri türüne yönlendirmeniz gerekir. Bu, herhangi bir SQL istemcisi ile çalışır, ancak \setyalnızcapsql

Yukarıdakiler Postgres 9.2 veya üstünü gerektirir.

Önceki sürümlerde, değişkenin postgresql.confkullanılmadan önce bildirilmesi gerekiyordu , bu yüzden kullanılabilirliğini bir şekilde sınırladı. Aslında değişken tamamen değil, ama esas olarak önek olan config "class". Ancak önek tanımlandıktan sonra, herhangi bir değişken değişmeden kullanılabilirpostgresql.conf


3
@BrijanElwadhi: evet bu işlemsel.
a_horse_with_no_name

2
Bir yan not olarak: Bazı kelimeler değişen örneğin saklıdır set session my.vars.id = '1';etmek set session my.user.id = '1';verecektirERROR: syntax error at or near "user"
dominik

2
@BrijanElwadhi: Kullanmak gerekir değişken işlem özgü yapmak için: SET LOCAL .... sessionDeğişken sürece bağlantı olduğu gibi yürürlükte olacaktır. localİşlem de kapsamlı.
Eugen Konkov

Sen, tırnak bu tip bir kısıtlama etrafında alabilirsiniz mesela. @dominik, beklendiği gibi çağrı çalışır. set session "my.user.id" = '1';current_setting('my.user.id')
Miles Elam

58

Müşterinize bağlıdır.

Ancak, psql istemcisini kullanıyorsanız, aşağıdakileri kullanabilirsiniz:

my_db=> \set myvar 5
my_db=> SELECT :myvar  + 1 AS my_var_plus_1;
 my_var_plus_1 
---------------
             6

Metin değişkenleri kullanıyorsanız alıntı yapmanız gerekir.

\set myvar 'sometextvalue'
select * from sometable where name = :'myvar';

1
\setküçük harf olmalı
deluan

db = # \ set profile_id 102 db = #: profile_id; HATA: "102" satırında veya yakınında sözdizimi hatası LINE 1: 102; ^
AlxVallejo

1
@AlxVallejo deyim ve psql konsolunda kullanmak zorunda . db=> \set someid 8292 db=> SELECT * FROM sometable WHERE id = :someid;
everis

21

Pl / PgSQL dışında bir Temp Tablosu kullanma

Pl / pgsql veya diğer pl / * dilini önerildiği gibi kullanmanın dışında, bu düşünebildiğim tek olasılık.

begin;
select 5::int as var into temp table myvar;
select *
  from somewhere s, myvar v
 where s.something = v.var;
commit;

13

Geçici tablolardan yararlanmayı kolaylaştırmak için @ DarioBarrionuevo'nun cevabına bir iyileştirme önermek istiyorum .

DO $$
    DECLARE myvar integer = 5;
BEGIN
    CREATE TEMP TABLE tmp_table ON COMMIT DROP AS
        -- put here your query with variables:
        SELECT * 
        FROM yourtable
        WHERE id = myvar;
END $$;

SELECT * FROM tmp_table;

DO bloğunu çözmek için güzel bir çözüm veri seti döndüremez!
CodeFarmer

PostgreSQL 11.0'da, böyle bir sorgu 1içeriği yerine (muhtemelen satır sayısı) geri döner tmp_table.
Ed Noepel

9

Bu çözüm, fei0x tarafından önerilene dayanmaktadır, ancak sorgudaki sabitlerin değer listesine katılmaya gerek olmaması avantajına sahiptir ve sabitler, sorgunun başlangıcında kolayca listelenebilir. Ayrıca özyinelemeli sorgularda da çalışır.

Temel olarak, her sabit, bir yan tümcesinde bildirilen ve daha sonra sorgunun geri kalan kısmında herhangi bir yere çağrılabilen tek değerli bir tablodur .

  • İki sabitli temel örnek:
WITH
    constant_1_str AS (VALUES ('Hello World')),
    constant_2_int AS (VALUES (100))
SELECT *
FROM some_table
WHERE table_column = (table constant_1_str)
LIMIT (table constant_2_int)

Alternatif kullanabilirsiniz SELECT * FROM constant_nameyerine TABLE constant_namehangi postgresql farklı diğer sorgu diller için geçerli olmayabilir.


6

İşte PREPARE ifadelerini kullanan bir örnek . Hala kullanamazsınız ?, ancak $ngösterimi kullanabilirsiniz :

PREPARE foo(integer) AS
    SELECT  *
    FROM    somewhere
    WHERE   something = $1;
EXECUTE foo(5);
DEALLOCATE foo;

Oldukça iyi çalışıyor! Teşekkürler.
Rui Carvalho

4

Doğru, tek değerli bir değişken beyan etmenin canlı ve net bir yolu yoktur, yapabileceğiniz şey

with myVar as (select "any value really")

daha sonra bu yapıda depolanan değere erişmek için

(select * from myVar)

Örneğin

with var as (select 123)    
... where id = (select * from var)

3

Araç özelliklerine başvurabilirsiniz. DBeaver'ın kendi özel sözdiziminde olduğu gibi:

@set name = 'me'
SELECT :name;
SELECT ${name};

DELETE FROM book b
WHERE b.author_id IN (SELECT a.id FROM author AS a WHERE a.name = :name);

Bu kullanılabilir daha yakın: DBeaver listeleri destekler ve döngü olup olmadığını bakmak için gidiyorum: birden çok şema için aynı sql uygulamak gerekir ve liste bunları uygulamak için şemaları olacaktır.
javadba

1

DBeaver'da, kodlarda olduğu gibi sorgularda parametreleri kullanabilirsiniz, böylece bu çalışır:

SELECT *
FROM somewhere
WHERE something = :myvar

Sorguyu çalıştırdığınızda DBeaver sizden: myvar değerini soracak ve sorguyu çalıştıracaktır.

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.