PostgreSQL 7 min read

PostgreSQLの文字列結合 ― ||がNULLになる・concatとstring_aggの使い分け

※この記事にはアフィリエイト広告(プロモーション)が含まれます。

PostgreSQL で文字列をつなぐ方法は、|| 演算子と concat 関数の2つです。違いは NULL の扱いです。この記事の出力は PostgreSQL 18.6(Ubuntu 26.04)で採りました。

まず見る(結論)

SELECT 'abc' || NULL                     AS pipe_null,    -- NULL
       concat('abc', NULL)               AS concat_null,  -- abc
       concat_ws('-', 'a', NULL, 'b')    AS ws,           -- a-b
       'abc' || coalesce(NULL, '')       AS coalesced;    -- abc

-- 複数行を1つにまとめる(MySQL の GROUP_CONCAT)
SELECT dept, string_agg(name, ',' ORDER BY id) FROM emp GROUP BY dept;
  • || はどちらかが NULL なら結果が NULL。concat は NULL を空文字として扱う
  • string_agg は第1引数が文字列型でないと function string_agg(integer, unknown) does not exist。::text を付ける

NULL の扱い

次の表で、name || ' ' || mid と concat_ws(' ', name, mid) を比べました。

 id |  pipe   |   ws
----+---------+---------
  1 | 佐藤 一 | 佐藤 一
  2 |         | 鈴木          -- mid が NULL
  3 | 高橋 二 | 高橋 二
  4 |         |               -- name も mid も NULL

psql は NULL を空欄で表示するので、id=2 の pipe は空文字ではなく NULL です(IS NULL が t)。concat_ws は NULL の引数を区切り文字ごと飛ばすため、id=2 は 鈴木 だけになりました。

UPDATE でも同じです。UPDATE emp SET name = name || '様' を実行すると、name が NULL の行は NULL のまま残りました。エラーも警告も出ません。

format('%s-%s', 'a', NULL) は a- になります。format も NULL を空文字として扱います。

数値・日付との結合

SELECT 'No.' || 5, 5 || '番', 'a' || current_date, 'a' || 1.50;
 No.5 | 5番 | a2026-10-31 | a1.50

SELECT 1 || 2;
ERROR:  operator does not exist: integer || integer

SELECT 'a' + 'b';
ERROR:  operator is not unique: unknown + unknown

両方が数値のときは 1::text || 2::text か concat(1, 2) と書きます(どちらも 12)。

char 型の末尾の空白

SELECT 'ab'::char(5) || 'x', concat('ab'::char(5), 'x'), 'ab'::varchar(5) || 'x';
 abx | ab   x | abx

char(n) の値を || でつなぐと、埋められた空白が落ちて abx になりました。concat では空白が残り、ab x になります。

string_agg で複数行をまとめる

SELECT dept, string_agg(name, ',' ORDER BY id) AS names FROM emp GROUP BY dept;
 dept |   names
------+-----------
 営業 | 佐藤,鈴木
 開発 | 高橋,田中        -- id=4 の name(NULL)は含まれない
書き方 結果
group_concat(name) ERROR: function group_concat(text) does not exist
string_agg(id, ',') ERROR: function string_agg(integer, unknown) does not exist
string_agg(id::text, ',' ORDER BY id) 1,2,3,4,5
string_agg(DISTINCT dept, ',' ORDER BY dept) 営業,開発
string_agg(DISTINCT dept, ',' ORDER BY id) ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list
対象が0行 空文字ではなく NULL

NULL も文字として残したいときは array_to_string の第3引数を使います。

SELECT array_to_string(array_agg(name ORDER BY id), ',', '(null)') FROM emp;
 佐藤,鈴木,高橋,(null),田中

ORDER BY を書かないと並び順は保証されません。順序に意味があるときは集約関数の中に ORDER BY を書きます。

関連: PostgreSQLでNVLの代わりにCOALESCEを使う / PostgreSQLのtext型とvarchar / PostgreSQLのto_charで日付を書式化する

PostgreSQL をもっと深く知るための本

PostgreSQL実践入門 ──アーキテクチャ、運用監視、性能改善

技術評論社・2026年2月

アーキテクチャから運用監視・性能改善までを扱う。付録に PostgreSQL 18 の新機能と設定項目の差分がある。

Amazonで見る

[改訂3版]内部構造から学ぶPostgreSQL ―設計・運用計画の鉄則

技術評論社・2022年11月・PostgreSQL 14 ベース

内部構造の理解から、設計と運用計画の立て方を学ぶ。

Amazonで見る

Amazonのアソシエイトとして、FIRE SE は適格販売により収入を得ています。