PostgreSQLクエリで変数を宣言する方法


240

PostgreSQL 8.3クエリで使用する変数を宣言するにはどうすればよいですか?

MS SQL Serverでこれを行うことができます:

DECLARE @myvar INT
SET @myvar = 5

SELECT *
FROM somewhere
WHERE something = @myvar

PostgreSQLで同じようにするにはどうすればよいですか?ドキュメントによると、変数は単に「名前タイプ」として宣言されていますが、これにより構文エラーが発生します。

myvar INTEGER;

誰かが正しい構文の例を教えてもらえますか?


2
PostgreSQLだけで実行できます。この関連の質問への答えを参照してくださいstackoverflow.com/questions/766657/...
ショーン・ビーン

2
この関連の答えは、より良い答えを持っている:stackoverflow.com/questions/13316773/...
アーウィンBrandstetter

回答:


113

PostgreSQLにはそのような機能はありません。pl / PgSQL(または他のpl / *)でのみ実行でき、プレーンSQLでは実行できません。

例外はWITH ()、変数として、または変数としても機能するクエリtupleです。一時的な値のテーブルを返すことができます。

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) > ...;

変数として使用されているこのCTEの方法を試しました。しかし、CTE内のさまざまなデータ変更クエリが互いの影響を確認できるとは限らないという問題にすぐに遭遇しました。複数のクエリでその変数を使用する必要があるため、複数のCTEを使用する必要がありました。
Zia Ul Rehman Mughal

227

私はWITHを使用して同じ目標を達成しました。これはエレガントなものにはほど遠いですが、同じことを行うことができます。この例では、それは本当にやり過ぎです。これも特にお勧めしません。

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

2
これは、変数が必要になるほとんどのインスタンスに最適です。ただし、LIMITに変数を使用したい場合(変数を含めることはできません)、\setShahriar Aghajaniの回答で提案されているように使用します。
cimmanon 2013年

1
これは、リレーショナルデータをインポートする移行スクリプトがある場合に最適です。明らかに、リレーショナルデータが指定されているシーケンスIDはわかりません。
Relequestual 2015

3
私はこのアプローチを試してみて、おそらくより良い方法を見つけました。JOIN myconstants ON trueそれから、副選択を行う必要はありません。
vektor 2015

7
これは単一のクエリ内でのみ機能WITHし、トランザクション内のクエリ間でCTEを共有することはできません。
Daenyth、2016

2
古い質問ですが、ここにバリエーションがあります:WITH constants AS (SELECT 5 AS var) SELECT * FROM somewhere CROSS JOIN constants WHERE someting=var;。単一行のテーブル式を持つCROSS JOINは、実際のテーブルのすべての行のデータを仮想的に複製し、式を単純化します。
Manngo 2016年

82

PLPGSQLでこれを試すこともできます:

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;

上記にはPostgres 9.0以降が必要です。


1
DOステートメントはPostgreSQL 9.0で追加され、8.3では機能しません。
ジョニー

14
CREATE TABLEではなく、CREATE TEMPORARY TABLEまたはCREATE TEMP TABLEを使用してください。しかし、それ以外の場合は問題ありません。
Stefan Steiger

60

動的構成設定

このために動的構成設定を「乱用」することができます。

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

構成設定は常にvarchar値であるため、使用する場合は正しいデータ型にキャストする必要があります。これはどのSQLクライアントでも機能しますが\setpsql

上記にはPostgres 9.2以降が必要です。

以前のバージョンでは、変数はpostgresql.conf使用する前に宣言する必要があったため、使いやすさが多少制限されていました。実際には完全に変数ではなく、本質的に接頭辞である構成「クラス」。しかし、接頭辞が定義されると、変数を変更せずに使用できますpostgresql.conf


3
@BrijanElwadhi:はい、それはトランザクションです。
a_horse_with_no_name 2017

2
set session my.vars.id = '1';set session my.user.id = '1';ERROR: syntax error at or near "user"
余談です

2
@BrijanElwadhi:変数トランザクションを固有のものにするには、以下を使用する必要がありますSET LOCAL ...session変数は、限り、あなたの接続があるとして有効になります。localトランザクションにスコープされます。
Eugen Konkov

あなたは、引用符でその制限を回避することができます例えば。@dominik、期待通りの呼び出しが動作します。set session "my.user.id" = '1';current_setting('my.user.id')
Miles Elam

58

それはあなたのクライアントに依存します。

ただし、psqlクライアントを使用している場合は、以下を使用できます。

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

テキスト変数を使用している場合は、引用する必要があります。

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

1
\set小文字である必要があります
deluan

db =#\ set profile_id 102 db =#:profile_id; エラー:「102」またはその近くの構文エラー1行目:102; ^
AlxVallejo

1
@AlxVallejoをステートメントとpsqlコンソールで使用する必要があります。 db=> \set someid 8292 db=> SELECT * FROM sometable WHERE id = :someid;
everis

21

pl / PgSQL外での一時テーブルの使用

提案されているようにpl / pgsqlまたは他のpl / *言語を使用する以外に、これが私が考え得る唯一の他の可能性です。

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

13

@DarioBarrionuevoの回答の改善を提案して、一時テーブルの活用をより簡単にします。

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ブロックを解決するための優れたソリューションはデータセットを返すことができません!
CodeFarmer 2018年

PostgreSQL 11.0では、このようなクエリは1の内容ではなく(おそらく行数)を返しますtmp_table
エドノペル

9

このソリューションはfei0xによって提案されたものに基づいていますますが、クエリの定数の値リストを結合する必要がなく、クエリの最初に定数を簡単にリストできるという利点があります。また、再帰クエリでも機能します。

基本的に、すべての定数はWITH句で宣言された単一値のテーブルであり、クエリの残りの部分の任意の場所で呼び出すことができます。

  • 2つの定数の基本的な例:
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)

SELECT * FROM constant_name代わりに、TABLE constant_namepostgresqlとは異なる他のクエリ言語では無効になる可能性のある代わりに使用できます。



4

確かに、単一値変数を宣言するための鮮明で明確な方法はありません。

with myVar as (select "any value really")

次に、この構造に格納されている値にアクセスするには、次のようにします。

(select * from myVar)

例えば

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

3

ツールの特別な機能に頼ることができます。DBeaver独自の構文のように:

@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);

これは使いやすいです:DBeaverがリストとループをサポートしているかどうかを調べます。同じSQLを複数のスキーマに適用する必要があり、リストはそれらを適用するスキーマのものになります。
javadba

1

DBeaverでは、コードの場合と同じようにクエリでパラメーターを使用できるため、これは機能します。

SELECT *
FROM somewhere
WHERE something = :myvar

クエリを実行すると、DBeaverは:myvarの値を尋ね、クエリを実行します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.