※この記事にはアフィリエイト広告(プロモーション)が含まれます。
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で日付を書式化する