Query Go
文字列連結の書き方 - 文字列連結の方言 (|| / CONCAT / +) の使い方・オプション・サンプル

文字列連結の書き方 - 文字列連結の方言 (|| / CONCAT / +)

文字列連結の演算子は RDBMS で異なる。標準の || / MySQL の CONCAT / SQL Server の + と NULL の扱い

概念図

文字列連結の方言 (|| / CONCAT / +) diagram

構文

sql
a || b  /  CONCAT(a, b)  /  a + b

サンプル

フルネーム結合の 3 パターン

sql
-- 標準 / PostgreSQL / SQLite / Oracle
SELECT first_name || ' ' || last_name AS full_name FROM users;

-- MySQL (|| は論理 OR と解釈される)
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;
-- SET sql_mode = 'PIPES_AS_CONCAT'; を設定すれば || も使える

-- SQL Server
SELECT first_name + ' ' + last_name AS full_name FROM users;
-- または
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;

文字列連結演算子の歴史

ANSI SQL 標準は || を文字列連結演算子と定めています。PostgreSQL / SQLite / Oracle / DB2 はこれに従っていますが、MySQL は歴史的事情で || を論理 OR として扱い、SQL Server は加算と同じ + を連結に転用しています。

近年はほぼ全ての RDBMS で CONCAT() 関数がサポートされたため、移植性重視なら CONCAT() が現実的な選択肢です。

RDBMS 別比較表

RDBMS演算子関数NULL を含むとき
PostgreSQL||CONCAT()|| は NULL 伝播、CONCAT() は NULL を空文字扱い
MySQL|| は OR (sql_mode 次第)CONCAT()CONCAT() は 1 つでも NULL なら結果 NULL
SQLite||なし (3.44+ で concat())|| は NULL 伝播
SQL Server+CONCAT() (2012+)+ は NULL 伝播、CONCAT() は NULL を空文字扱い
Oracle||CONCAT() (2 引数のみ)|| も NULL を空文字扱い (独自仕様)

NULL の扱いの違いが一番の罠

ほとんどの RDBMS で「NULL を含む連結は NULL」になります。つまり middle_name が NULL のユーザーは first || ' ' || middle || ' ' || last で全体が NULL になってしまいます。

対策としては COALESCE(middle, '') で空文字に落とすか、NULL を空文字扱いしてくれる CONCAT()(PostgreSQL / SQL Server)や CONCAT_WS()(区切り文字付き・MySQL / PostgreSQL / SQL Server)を使います。

sql
-- NULL 安全な例 (PostgreSQL / MySQL / SQL Server)
SELECT CONCAT_WS(' ', first_name, middle_name, last_name) AS full_name
FROM users;

-- 古典的な書き方 (全 RDBMS)
SELECT first_name
       || COALESCE(' ' || middle_name, '')
       || ' ' || last_name AS full_name
FROM users;

SQL Server で + が暗黙の型変換で壊れる

SQL Server の + は文字列でも数値でも使える多重定義演算子です。両辺が数値型だと加算になってしまい、'Order ' + 42 のような書き方は「文字列 + int」で暗黙変換エラーになります。

明示的に CAST(42 AS VARCHAR) するか、型を気にしなくてよい CONCAT() を使うのが安全です。

sql
-- NG: 暗黙変換エラー
SELECT 'Order ' + 42;

-- OK
SELECT 'Order ' + CAST(42 AS VARCHAR(10));
SELECT CONCAT('Order ', 42);

関連トピック