コマンド道場

文字列関数(連結・文字数・大文字小文字)の使い方

元の値から、新しい文字列を作る

shain社員

shain_idname
1鈴木
2佐藤
3田中
4中村
5小林
6加藤

CONCAT で作った列を足す作った結果

shain_idnamekeishou
1鈴木鈴木 さん
2佐藤佐藤 さん
3田中田中 さん
4中村中村 さん
5小林小林 さん
6加藤加藤 さん

CONCAT(name, ' さん') AS keishou

  • 青い列= 式から作った列。元の表には無い列です
  • 社員 18作った結果 18(行数は変わりません。減らすのは WHERE の仕事です)

行は 1 行も減っていません。文字列関数は値を作るだけで、行の数には触れません。

文字列関数は「行を絞る」のではなく「値を作る」道具です。 ここでは使用頻度の高い連結・文字数・大文字小文字を扱います。いちばん事故が多いのは連結で、NULL が 1 つ混ざるだけで結果が丸ごと消える書き方があります。

この書き方が使えない製品があります そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / Oracle Database

  • SQL Server では使えません|| による文字列連結・LENGTH(文字数)

未確認: IBM Db2

製品ごとの対応表(根拠つき)を見る

このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。

01連結には 2 つの書き方がある

結論: || 演算子と CONCAT() 関数のどちらでも文字列をつなげます。

  • a || b || c … 標準 SQL の演算子。短く書ける
  • CONCAT(a, b, c) … 関数。引数をいくつでも並べられる

見た目が違うだけに見えますが、NULL が混ざったときの動きが正反対です(次の節)。ここを知らずに使い分けると、本番でだけ空欄が出ます。

⚠️ || は SQL Server では使えません+ を使います)。移植の予定があるなら CONCAT() のほうが安全です。使えない製品がある例には自動で注記が出ます。

1 行ずつ、何をしているか
  1. SELECT s.name,元の列
  2. b.busho_name,つなげたい相手の列
  3. s.name || '/' || b.busho_nameつないで新しい値を作る
  4. AS shozoku作った列に名前を付ける
  5. FROM shain sどの表を見るか
  6. LEFT JOIN busho b ON b.busho_id = s.busho_id部署名を引いてくる

つなぐ相手は同じ表の列でも、結合した別の表の列でも構いません。文字列以外(数値など)も多くの製品では自動で文字列に直されます。

|| でつなぐ
SELECT name || ' さん' AS keishou
FROM shain
ORDER BY shain_id;
keishou
鈴木 さん
佐藤 さん
田中 さん
中村 さん
小林 さん

18 … うち先頭 5 行を表示

⚠️ この書き方は SQL Server では使えません(|| による文字列連結)。製品ごとの対応表

CONCAT でつなぐ(結果は同じ)
SELECT CONCAT(name, ' さん') AS keishou
FROM shain
ORDER BY shain_id;
keishou
鈴木 さん
佐藤 さん
田中 さん
中村 さん
小林 さん

18 … うち先頭 5 行を表示

同じ結果です。ここまでは書き方の好みの問題に見えます。

02⚠️ よくある間違い:NULL が混ざると結果が変わる

結論: || は NULL が 1 つでも混ざると全体が NULL になり、CONCAT() は NULL を空文字として扱います。

これは好みの差ではなく挙動の差です。所属が未設定の社員を外部結合で引くと、部署名が NULL になります。そこで || を使うと、名前まで含めて行全体の値が消えます

エラーは出ません。18 行のうち 2 行だけが空欄になるので、件数の少ないデータでは気づかないまま本番に出ます。

対処は 2 つ。

  • CONCAT() を使う … NULL の部分だけが空文字になる
  • COALESCE() で先に埋める … 「所属なし」のような意味のある文字を出せる

表示に使うなら 2 つ目が親切です。空欄より「所属なし」と書いてあるほうが、データが無いのか処理を間違えたのかが読み手に伝わります。

|| だと行ごと NULL になる
SELECT s.name, b.busho_name,
       s.name || '/' || b.busho_name AS pipe_de
FROM shain s
  LEFT JOIN busho b ON b.busho_id = s.busho_id
ORDER BY s.shain_id;
namebusho_namepipe_de
鈴木経営鈴木/経営
佐藤開発佐藤/開発
田中開発田中/開発
中村開発中村/開発
小林開発小林/開発
加藤基盤加藤/基盤
吉田基盤吉田/基盤
山田営業山田/営業
高橋営業高橋/営業
伊藤営業伊藤/営業
松本営業松本/営業
井上マーケ井上/マーケ
木村マーケ木村/マーケ
清水管理清水/管理
斎藤管理斎藤/管理
山本管理山本/管理
渡辺NULLNULL
大野NULLNULL

18

末尾の 2 行(渡辺・大野)は名前も消えて NULL です。部署名が NULL なだけなのに、つないだ結果は全部失われます。

⚠️ この書き方は SQL Server では使えません(|| による文字列連結)。製品ごとの対応表

CONCAT なら名前は残る
SELECT s.name, b.busho_name,
       CONCAT(s.name, '/', b.busho_name) AS concat_de
FROM shain s
  LEFT JOIN busho b ON b.busho_id = s.busho_id
ORDER BY s.shain_id;
namebusho_nameconcat_de
鈴木経営鈴木/経営
佐藤開発佐藤/開発
田中開発田中/開発
中村開発中村/開発
小林開発小林/開発
加藤基盤加藤/基盤
吉田基盤吉田/基盤
山田営業山田/営業
高橋営業高橋/営業
伊藤営業伊藤/営業
松本営業松本/営業
井上マーケ井上/マーケ
木村マーケ木村/マーケ
清水管理清水/管理
斎藤管理斎藤/管理
山本管理山本/管理
渡辺NULL渡辺/
大野NULL大野/

18

末尾の 2 行が「渡辺/」「大野/」になりました。NULL の部分だけが空文字として扱われています。

COALESCE で埋めてからつなぐ
SELECT s.name, b.busho_name,
       s.name || '/' || COALESCE(b.busho_name, '所属なし') AS umeta
FROM shain s
  LEFT JOIN busho b ON b.busho_id = s.busho_id
ORDER BY s.shain_id;
namebusho_nameumeta
鈴木経営鈴木/経営
佐藤開発佐藤/開発
田中開発田中/開発
中村開発中村/開発
小林開発小林/開発
加藤基盤加藤/基盤
吉田基盤吉田/基盤
山田営業山田/営業
高橋営業高橋/営業
伊藤営業伊藤/営業
松本営業松本/営業
井上マーケ井上/マーケ
木村マーケ木村/マーケ
清水管理清水/管理
斎藤管理斎藤/管理
山本管理山本/管理
渡辺NULL渡辺/所属なし
大野NULL大野/所属なし

18

「渡辺/所属なし」になりました。空欄ではなく意味のある文字が出るので、読み手が判断できます。

⚠️ この書き方は SQL Server では使えません(|| による文字列連結)。製品ごとの対応表

03文字数は LENGTH で数える

結論: LENGTH() が返すのは文字数です。 この実行環境では、全角文字も 1 文字として数えます。

「バイト数ではないか」と迷う部分ですが、製品と型と設定によって答えが変わります。バイト数を返す製品もあれば、文字数を返す製品もあります。日本語を扱うなら、自分の環境でどちらなのかを 1 回試して確かめてください

⚠️ SQL Server に LENGTH はありませんLEN を使います)。名前が違うだけなので移植は簡単ですが、そのままでは動きません。

全角も 1 文字
SELECT busho_name, LENGTH(busho_name) AS moji
FROM busho
ORDER BY busho_id;
busho_namemoji
経営2
開発2
営業2
管理2
基盤2
法務2
マーケ3

7

漢字 2 文字の部署は 2、カタカナ 3 文字の「マーケ」は 3 です。バイト数なら 6 や 9 になるので、この環境は文字数を返していると分かります。

⚠️ この書き方は SQL Server では使えません(LENGTH(文字数))。製品ごとの対応表

04大文字小文字は UPPER / LOWER でそろえる

結論: UPPER()LOWER() は英字の大小を変換します。 日本語には効きません。

いちばんの使い道は比較の前処理です。文字列の比較や LIKE は、環境によって大文字小文字を区別したりしなかったりします。両側を LOWER() で揃えてから比べれば、どの環境でも同じ結果になります。

  • WHERE LOWER(mail) = LOWER('Taro@Example.com')

⚠️ ただし、列に関数をかけるとその列の索引が使えなくなります。件数の多い表で常用するなら、保存するときに小文字で揃えておくか、式に対する索引を作るのが定石です。

英字には効く
SELECT UPPER('abcXYZ') AS ue,
       LOWER('abcXYZ') AS shita;
ueshita
ABCXYZabcxyz

1

日本語には効かない
SELECT busho_name, UPPER(busho_name) AS ue
FROM busho
ORDER BY busho_id;
busho_nameue
経営経営
開発開発
営業営業
管理管理

7 … うち先頭 4 行を表示

元の値と同じです。大文字小文字という区別が無い文字は、そのまま返ります。

そろえてから比べる
SELECT 'ABC' = 'abc'               AS sonomama,
       LOWER('ABC') = LOWER('abc') AS soroeta;
sonomamasoroeta
falsetrue

1

左は false、右は true です。この環境は大文字小文字を区別するので、そろえないと一致しません。

05移植しやすい書き方を選ぶ

結論: 同じことができる書き方が複数あるときは、通る製品が多いほうを選んでおくと後で困りません。

  • 連結 … CONCAT() のほうが広く通ります|| は SQL Server で使えません
  • 文字数 … LENGTH は SQL Server では LEN です。関数名を変えるだけなので移植の負担は小さめ
  • 大文字小文字 … UPPER / LOWER はどの製品にもあります

各例の下に出ている注記は、構文ごとに調べた対応表から自動で導いたものです。手で書いた覚え書きではないので、対応表を更新すれば注記も一緒に変わります。

このページで扱っていない関数(部分文字列の取り出し、前後の空白除去、置換など)は、まだ対応表に載せていないため注記を出せません。練習問題のほうで扱っています。

CONCAT は数値もそのまま渡せる
SELECT CONCAT(name, '(', busho_id, ')') AS hyouji
FROM shain
ORDER BY shain_id;
hyouji
鈴木(1)
佐藤(2)
田中(2)
中村(2)
小林(2)
加藤(5)
吉田(5)
山田(3)
高橋(3)
伊藤(3)
松本(3)
井上(7)
木村(7)
清水(4)
斎藤(4)
山本(4)
渡辺()
大野()

18

busho_id は数値ですが、文字列に直さずに渡せています。末尾 2 行は所属が NULL なので、その部分だけが空になります。

自分で打ってみる

このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。

押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。

解いてみる

読んだだけでは書けるようになりません。実行結果で採点します。

ここで出てくる関数を引く

関連するトピック

  • NULL を扱う関数COALESCE で NULL を埋めてから連結する話の続きです。
  • LIKE 述語文字列を形で探すときはこちらです。
  • 比較演算子文字列の大小がどう決まるかの話です。
  • CASE 式値によって出す文字を変えたいときに組み合わせます。

根拠(一次情報)