38

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

を使おうと思っているのですconcat(...)が、何か良い方法はありませんか?
これを行う最善の方法は何ですか?

4

3 に答える 3

90

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

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

null 値を除外できる場合||でも、古き良き (SQL 標準) 連結演算子が最良の選択であり、@luis の答えは問題ありません。

SELECT col_a || col_b;

いずれかの列が null になる可能性がある場合、その場合、結果は null になります。あなたはで守ることができますCOALESCE

SELECT COALESCE(col_a, '') || COALESCE(col_b, '');

しかし、それは引数が増えるとすぐに退屈になります。これは、すべての引数が nullであっても、null を返すことconcat()はありません。ドキュメントごと

NULL 引数は無視されます。

SELECT concat(col_a, col_b);

両方の選択肢の残りのコーナー ケースは、すべての入力列が nullであり、その場合でも空の string を取得します''が、代わりに 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)です。また、すべての列が nullの場合にのみ、行の型がnull になります。詳細な説明:

また、concat_ws()要素間にセパレーターを追加するために使用します ( ws「セパレーター付き」の場合)。


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

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関数ラッパーを使用してこれを回避できます。例:

于 2012-09-07T14:45:06.223 に答える
17

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

設定する:

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 | ナニュエット | ニューヨーク |
+---------+--------+-------+

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

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

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

SELECT *, tbl.combined FROM tbl;

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

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

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

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

于 2012-09-07T03:23:41.367 に答える
16

文字列連結関数を確認しましたか?何かのようなもの:

update table_c set column_a = column_b || column_c 

動作するはずです。詳細はこちら

于 2012-09-07T02:49:58.810 に答える