web-dev-qa-db-ja.com

2つの列を組み合わせて、1つの新しい列に追加します

PostgreSQLでは、SQLステートメントを使用して2つの列を結合し、それらから新しい列を作成したいと思います。

concat(...)の使用を考えていますが、もっと良い方法はありますか?
これを行う最良の方法は何ですか?

30
Rock

一般的に、私は @ kgrittnのアドバイス に同意します。頑張れ。

ただし、 concat() に関する基本的な質問に対処するには、新しい関数concat()null値を処理する必要がある場合に便利です-そして、nullはあなたの質問でも参照するものでも除外されていません。

null値を除外できる場合、古き良き(SQL標準)連結演算子 _||_ はまだ最良の選択、および @ luis 'answer は問題ありません。

_SELECT col_a || col_b;
_

Ifいずれかの列がヌルになる可能性がある場合、その場合、結果はヌルになります。 COALESCEで防御できます:

_SELECT COALESCE(col_a, '') || COALESCE(col_b, '');
_

しかし、それはより多くの議論ですぐに退屈になります。ここでconcat()が入力され、neverは、all引数がnullであってもnullを返しません。 ドキュメントごと

NULL引数は無視されます。

_SELECT concat(col_a, col_b);
_

両方の選択肢のremaining corner caseは、all入力列はnullです。この場合、空の文字列_''_を取得しますが、代わりにnullが必要な場合があります(少なくとも私はそうします)。 1つの可能な方法:

_SELECT CASE
          WHEN col_a IS NULL THEN col_b
          WHEN col_b IS NULL THEN col_a
          ELSE col_a || col_b
       END
_

これは、より多くの列でより複雑になります。繰り返しますが、concat()を使用しますが、特別な条件のチェックを追加します。

_SELECT CASE WHEN (col_a, col_b) IS NULL THEN NULL
            ELSE concat(col_a, col_b) END;
_

これはどのように機能しますか?
_(col_a, col_b)_は、行タイプの式ROW (col_a, col_b)の略記法です。また、行タイプは、all列がnullの場合にのみnullです。詳細な説明:

また、 concat_ws() を使用して、要素間にセパレータを追加します(__ws_ .. "withセパレータ」)。


ケビンの答えのような表現:

_SELECT $1.zipcode || ' - ' || $1.city || ', ' || $1.state;
_

postgreSQL 8.3でnull値を準備するのは面倒です(concat()なし)。 (多くの)1つの方法:

_SELECT COALESCE(
         CASE
          WHEN $1.zipcode IS NULL THEN $1.city
          WHEN $1.city IS NULL THEN $1.zipcode
          ELSE $1.zipcode || ' - ' || $1.city
         END, '')
       || COALESCE(', ' || $1.state, '');
_

関数のボラティリティはSTABLEのみです

ただし、concat()およびconcat_ws()STABLEではなくIMMUTABLE関数であり、データ型出力関数(_timestamptz_out_など)を呼び出すことができるため、注意してください。 )ロケール設定に依存します。 トムレーンによる説明

これにより、インデックス式での直接使用が禁止されます。結果が実際に不変であることを知っている場合IMMUTABLE関数ラッパーでこれを回避できます。ここの例:

66

そのように参照するために列を保存する必要はありません。これを試して:

設定する:

CREATE TABLE tbl
  (zipcode text NOT NULL, city text NOT NULL, state text NOT NULL);
INSERT INTO tbl VALUES ('10954', 'Nanuet', 'NY');

「適切なもの」があることがわかります。

\pset border 2
SELECT * FROM tbl;
 + --------- + -------- + ------- + 
 |郵便番号|市|状態| 
 + --------- + -------- + ------- + 
 | 10954 |ナニュエット| NY | 
 + --------- + -------- + ------- + 

ここで、テーブルのレコードタイプを唯一のパラメータとして使用する目的の「列名」を持つ関数を追加します。

CREATE FUNCTION combined(rec tbl)
  RETURNS text
  LANGUAGE SQL
AS $$
  SELECT $1.zipcode || ' - ' || $1.city || ', ' || $1.state;
$$;

これにより、次のようにテーブル名またはエイリアスが指定されている限り、テーブルの列であるかのように使用できる関数が作成されます。

SELECT *, tbl.combined FROM tbl;

次のように表示されます:

 + --------- + -------- + ------- + ----------------- --- + 
 |郵便番号|市|状態|結合| 
 + --------- + -------- + ------- + --------------- ----- + 
 | 10954 |ナニュエット| NY | 10954-ニューヨーク州ナニュエット| 
 + --------- + -------- + ------- + ----------- --------- + 

PostgreSQLは最初に実際の列をチェックしますが、見つからない場合、識別子がリレーション名またはエイリアスで修飾されている場合、上記のような関数を探し、行を引数として実行して戻ります。結果が列であるかのように。そのような「生成された列」でインデックスを作成することもできます。

重複データの各行で余分なスペースを使用したり、すべての挿入および更新でトリガーを起動したりしないため、多くの場合、これは代替手段よりも高速です。

15
kgrittn

文字列連結関数をチェックしましたか?何かのようなもの:

update table_c set column_a = column_b || column_c 

動作するはずです。もっと こちら

13
luis