2

1 つの条件に基づいて複数の列を生成する方法はありますか? 私の認識は次のようなものです:

SELECT

CASE WHEN condition_column = 'condition true' and (condition_column2 = 'condition true' or condition_column3 = 'condition true')

THEN column1 as new_column1
AND column2 as new_column2
AND column3 as new_column3

ELSE column2 as new_column1
AND column3 as new_column2
AND column1 as new_column3

これを行う私の現在の方法は次のようなものです:

SELECT

CASE WHEN condition_column = 'condition true' and (condition_column2 = 'condition true' or condition_column3 = 'condition true')
THEN column1 ELSE column2 END AS new_column1,

CASE WHEN condition_column = 'condition true' and (condition_column2 = 'condition true' or condition_column3 = 'condition true')
THEN column2 ELSE column3 END AS new_column2,

CASE WHEN condition_column = 'condition true' and (condition_column2 = 'condition true' or condition_column3 = 'condition true')
THEN column3 ELSE column1 END AS new_column3

しかし、複雑な条件の場合、これはステートメントの非常に長いリストになります。

4

1 に答える 1

2

まったく異なるアプローチを試す必要があります。これらのいずれか:

CTE / LEFT JOIN/UNION ALL

  1. CTEの最初のケースのすべての列を選択します。
  2. 2 番目のケースから既に選択されている行を除外します。
  3. UNION ALLCTEで。

WITH cte AS (
   SELECT tbl_id, col1, col2, col3
   FROM   tbl
   WHERE  condition_col = 'cond true'
   AND    'cond true' IN (condition_col2, condition_col3)
   )
SELECT t.tbl_id, t.col2 AS new1, t.col3 AS new2, t.col1 AS new3
FROM   tbl t
LEFT   JOIN cte c USING (tbl_id)
WHERE  c.tbl_id IS NULL

UNION ALL
TABLE cte
ORDER BY tbl_id

tbl_idこのシナリオでは主キーです。

配列

配列は、同じ基本型の値のみを保持できます。関連するすべての列が同じ型を共有している場合は、1 つの条件に基づいて配列全体を選択します。配列を再度ネスト解除するには、次のようなサブクエリを使用します。

SELECT tbl_id, a[1] AS new1, a[2] AS new2
FROM (
   SELECT tbl_id, CASE WHEN TRUE THEN ARRAY[col1, col2]
                                 ELSE ARRAY[col2, col3] END AS a
   FROM   tbl
   ) x;

異なる型の列がある場合は、すべてを同じ型にキャストtextできます。通常は次のレベルで (オプションでキャストバックします):

SELECT tbl_id, a[1] AS new1, a[2] AS new2
FROM (
   SELECT tbl_id, CASE WHEN TRUE THEN ARRAY[col1::text, col2::text]
                                 ELSE ARRAY[col2::text, col3::text] END AS a
   FROM   tbl
   ) x;

記録

サブクエリ レベルとキャスト タイプを回避するには、代わりにレコード タイプを使用できます。ここでの障害は、Postgres が登録済みの (既知の) レコード タイプのネストしか解除できないことです。


SELECT tbl_id, (CASE WHEN TRUE THEN (col1::text, col2::int)
                               ELSE (col2::text, col3::int) END).*
FROM   tbl;

匿名レコードの場合、次のようになります。

ERROR:  record type has not been registered

ただし、暗黙的に作成されたテーブルやビューの型、または で明示的に作成された型など、登録済みのレコード型CREATE TYPEを操作できます。このデモのために、型を明示的に作成します。

CREATE TYPE foo AS (new1 text, new2 int);

次に、単一の式に基づいて複数の列を選択CASEし、同じ手順でレコードのネストを解除できます。

SELECT tbl_id, (CASE WHEN TRUE THEN (col1::text, col2::int)::foo
                               ELSE (col2::text, col3::int)::foo END).*
FROM   tbl;

任意のタイプの列(同じタイプであっても) で機能します。括弧を囲むことは必須です。

アドホック クエリの場合、新しい型を永続化する必要はありません。代わりに、セッションで死ぬ一時テーブルを作成します。

CREATE TEMP TABLE foo (new1 text, new2 int);
SELECT ...
于 2013-06-08T18:27:54.890 に答える