これらの式を持つPostgres SELECT
ステートメントがあります。
,CASE WHEN (rtp.team_id = rtp.sub_team_id)
THEN 'testing'
ELSE TRIM(rtd2.team_name)
END AS testing_testing
,CASE WHEN (rtp.team_id = rtp.sub_team_id)
THEN 'test example'
ELSE TRIM(rtd2.normal_data)
END AS test_response
,CASE WHEN (rtp.team_id = rtp.sub_team_id)
THEN 'test example #2'
ELSE TRIM(rtd2.normal_data_2)
END AS another_example
私の特定のクエリには、出力がrtp.team_id = rtp.sub_team_id
はtrueと評価されます。同じ条件でCASE
ステートメントを何度も繰り返しています。
これらのCASE
式を組み合わせて、複数の列の出力を一度に切り替える方法はありますか?
LEFT JOIN
値の単一行LEFT JOIN
条件を使用して値の行を指定できます(これにより、一度評価します)。次に、 COALESCE()
を使用して、列ごとにフォールバック値を追加できます。
この構文のバリエーションは、複数の値を使用すると短く、わずかに速くなります-特に高価な/長い条件で興味深い:
SELECT COALESCE(x.txt1, trim(r2.team_name)) AS testing_testing
, COALESCE(x.txt2, trim(r2.normal_data)) AS test_response
, COALESCE(x.txt3, trim(r2.normal_data_2)) AS another_example
FROM rtp
JOIN rtd2 r2 ON <unknown condition> -- missing context in question
LEFT JOIN (
SELECT 'testing'::text AS txt1
, 'test example'::text AS txt2
, 'test example #2'::text AS txt3
) x ON rtp.team_id = rtp.sub_team_id;
派生テーブルx
はsingle行で構成されるため、それ以上の条件なしで結合しても問題ありません。
明示的な型キャストは、サブクエリで必要です。例ではtext
を使用しています(これは文字列リテラルのデフォルトです)。実際のデータ型を使用してください。構文ショートカットvalue::type
はPostgres固有であり、標準SQLにはcast(value AS type)
を使用します。
条件がTRUE
でない場合、x
のすべての値はNULLであり、COALESCE
が有効になります。
または、特定のケースではすべての候補値がテーブルrtd2
から取得されるため、元のCASE
条件を使用してLEFT JOIN
からrtd2
に、デフォルト値を持つ行にCROSS JOIN
を使用します。
SELECT COALESCE(trim(r2.team_name), x.txt1) AS testing_testing
, COALESCE(trim(r2.normal_data), x.txt2) AS test_response
, COALESCE(trim(r2.normal_data_2), x.txt3) AS another_example
FROM rtp
LEFT JOIN rtd2 r2 ON <unknown condition> -- missing context in question
AND rtp.team_id = rtp.sub_team_id
CROSS JOIN (
SELECT 'testing'::text AS txt1
, 'test example'::text AS txt2
, 'test example #2'::text AS txt3
) x;
結合条件とクエリの残りの部分に依存します。
さまざまな列が同じデータ型を共有している場合、サブクエリで配列を使用し、外側のSELECT
で展開できます。 :
SELECT x.combo[1], x.combo[2], x.combo[3]
FROM (
SELECT CASE WHEN rtp.team_id = rtp.sub_team_id
THEN '{test1,test2,test3}'::text[]
ELSE ARRAY[trim(r2.team_name)
, trim(r2.normal_data)
, trim(r2.normal_data_2)]
END AS combo
FROM rtp
JOIN rtd2 r2 ON <unknown condition>
) x;
列が同じデータ型を共有しない場合、より複雑になります。それらをすべてtext
にキャストする(またはオプションで外側のSELECT
に戻す)か、または...
カスタム複合型(行型)を使用して、さまざまな型の値を保持し、外側のSELECT
で単純に* -expandできます。 text
、integer
、date
の3つの列があるとします。 repeatedを使用するには、カスタムの複合型を作成します。
CREATE TYPE my_type (t1 text, t2 int, t3 date);
または既存のテーブルのタイプが一致する場合、テーブル名を複合タイプとして使用できます。
またはタイプtemporarilyのみが必要な場合は、TEMPORARY TABLE
を作成して、一時的なタイプをセッション:
CREATE TEMP TABLE my_type (t1 text, t2 int, t3 date);
単一トランザクションに対してもこれを行うことができます。
CREATE TEMP TABLE my_type (t1 text, t2 int, t3 date) ON COMMIT DROP;
次に、このクエリを使用できます。
SELECT (x.combo).* -- parenthesis required
FROM (
SELECT CASE WHEN rtp.team_id = rtp.sub_team_id
THEN ('test', 3, now()::date)::my_type -- example values
ELSE (r2.team_name
, r2.int_col
, r2.date_col)::my_type
END AS combo
FROM rtp
JOIN rtd2 r2 ON <unknown condition>
) x;
または単に(上記と同じ、より単純、より短く、おそらく理解しにくい):
SELECT (CASE WHEN rtp.team_id = rtp.sub_team_id
THEN ('test', 3, now()::date)::my_type
ELSE (r2.team_name, r2.int_col, r2.date_col)::my_type
END).*
FROM rtp
JOIN rtd2 r2 ON <unknown condition>;
CASE
式は、この方法ですべての列に対して1回評価されます。評価が簡単でない場合、サブクエリを持つ他のバリアントはより高速になります。
改善されるかどうかはわかりませんが、SELECT
をそれ自体と別の方法で結合できます。
SELECT
...,
'testing' AS testing_testing,
'test example' AS test_response,
'test example #2' AS another_example, ...
FROM ...
WHERE rtp.team_id = rtp.sub_team_id AND ...
UNION
SELECT
...,
TRIM(rtd2.team_name) AS testing_testing,
TRIM(rtd2.normal_data) AS test_response,
TRIM(rtd2.normal_data_2) AS another_example, ...
WHERE rtp.team_id <> rtp.sub_team_id AND ...;
列名は、最初のクエリと同じ順序で取り出すと仮定して、2番目のクエリから安全に省略できます。
共通テーブル式(CTE)を使用して、それぞれを個別のクエリにすることができます。この順序の変更が心配な場合は、サブクエリにして、ORDER BY
その周りに。