SQL:文字列と日付の操作
1学習の目的
- 文字列の連結・切り出し・置換ができるようになる。「田中商事(東京)」のような表示用の文字列を、保存されたデータから組み立てられるようになる。
- 日付を文字列として比較・加工できるようになる。「今月の注文だけ」「月別の売上」といった、日付が絡む実務の要求に応えられるようになる。
2基礎解説
| やりたいこと | 書き方 | 結果の例 |
|---|---|---|
| 連結する | name || '(' || area || ')' | 田中商事(東京) |
| 一部を切り出す | SUBSTR(order_date, 1, 7) | 2026-01 |
| 文字数を調べる | LENGTH(name) | 5 |
| 置き換える | REPLACE(name, 'PC', 'パソコン') | ノートパソコン |
- 文字列の連結は ||(環境によっては CONCAT())。name || '(' || area || ')' のように、文字列と列を自由に組み合わせられる。
- SUBSTR(文字列, 開始位置, 長さ) で一部を切り出せる。開始位置は1から数える(0ではない)。SUBSTR('2026-01-05', 1, 4) なら年の4文字。
- 日付は文字列として保存されることが多い('2026-01-05' の形式)。年→月→日の順で書かれていれば、文字列としての大小比較がそのまま日付の前後関係と一致する。
- ⚠ UPPER / LOWER は半角英数字にしか効かない。日本語の文字は変化しない。UPPER('ノートpc') は 'ノートPC' になるが、ひらがな・カタカナ・漢字はそのまま。
- LIKE(SQL02)と SUBSTR は役割が違う。「含むか調べる」なら LIKE、「一部を取り出す」なら SUBSTR。
現場使用例:氏名と敬称の連結、電話番号のハイフン整形、注文日から年月を取り出して月次集計、名前や住所の表記ゆれの一括置換。
-- 表示用の文字列を組み立てる SELECT name || '(' || area || ')' AS 表示名 FROM customers; -- → 田中商事(東京) -- 日付から年月だけを取り出す SELECT order_date, SUBSTR(order_date, 1, 7) AS 年月 FROM orders; -- → 2026-01-05 / 2026-01 -- 月別に集計する SELECT SUBSTR(order_date, 1, 7) AS 月, COUNT(*) AS 件数 FROM orders GROUP BY 月; -- 日付の範囲で絞り込む(文字列比較でそのまま使える) SELECT * FROM orders WHERE order_date >= '2026-02-01'; -- 文字を置き換える SELECT REPLACE(name, 'PC', 'パソコン') AS 新名称 FROM products WHERE id = 1; -- → ノートパソコン
3基本ドリル(10問)
1列4行。田中商事(東京)が先頭
|| で文字列と列をつなぐ。SELECT name || '(' || area || ')' AS label のように書く。
SELECT name || '(' || area || ')' AS label FROM customers;
|| は文字列をつなげる演算子。列と固定の文字列を自由に組み合わせられるので、表示用の文字列を組み立てるときによく使う。
A. "2026" B. "026-" C. "0-01" D. エラー 選択★☆☆無料
解答 == A
1文字目から4文字ぶん切り出す。
A
開始位置は1から数える。0からではない点に注意。「1文字目から4文字」なので年の部分がちょうど取れる。
2列7行。2026-01-05 / 2026-01 が先頭
SUBSTR(order_date, 1, 7) と書く。
SELECT order_date, SUBSTR(order_date, 1, 7) AS 年月 FROM orders;
「2026-01-05」の先頭7文字は「2026-01」。年月だけを取り出すこの形は、月次集計の下準備として頻出する。
SELECT name, ____(name) AS 文字数 FROM products;
2列7行。ノートPC が 5
「長さ」を意味する6文字の関数。
LENGTH
日本語も正しく1文字として数えられる(環境による)。「ノートPC」はノ・ー・ト・P・Cの5文字。
A. "ノートPC" B. "ノートpc"のまま C. 全角に変換される D. エラー 選択★☆☆無料
解答 == A
UPPERが効くのは半角英字だけ。日本語部分はどうなるか。
A
半角の pc だけが PC に変わり、「ノート」の部分は変化しない。UPPER/LOWERは日本語には効かないので、全角文字を大文字化しようとしても無意味。
5列3行。id 5,6,7
WHERE order_date LIKE '2026-02%' と書く。
SELECT * FROM orders WHERE order_date LIKE '2026-02%';
LIKE で前方一致にすれば「その月のすべて」が取れる。日付が文字列で保存されている前提の書き方。
SELECT * FROM orders WHERE order_date ____ '2026-01-31';
5列4行。1月の注文のみ
「以下」を表す比較演算子。日付は文字列として大小比較できる。
<=
年→月→日の順で書かれた日付文字列は、そのまま大小比較が成立する。'2026-01-31' <= '2026-02-01' が正しく判定される。
A. 特に問題ない B. 文字列としての大小比較が日付の前後と一致しなくなる C. エラーになって保存できない D. 自動でゼロ埋めされる 選択★★☆無料
解答 == B
'2026-1-9'(1月9日)と '2026-1-10'(1月10日)を文字列として比較すると。
B
'2026-1-10'(1月10日)は '2026-1-9'(1月9日)より文字列として小さくなってしまう('1'<'9'のため10日が9日より前と誤判定される)。日付は必ずゼロ埋めした形式(YYYY-MM-DD)で保存するのが鉄則。
2列7行。ノートPC → ノートパソコン
REPLACE(name, 'PC', 'パソコン') と書く。
SELECT name, REPLACE(name, 'PC', 'パソコン') AS 新名称 FROM products;
該当しない行はそのまま返る。「マウス」には PC が含まれないので変化しない。REPLACEは表記ゆれの一括修正にも使われる。
2列2行。2026-01 4 / 2026-02 3
SUBSTR で年月を作り、その別名で GROUP BY する。
SELECT SUBSTR(order_date, 1, 7) AS 月, COUNT(*) AS 件数 FROM orders GROUP BY 月;
SUBSTRで作った文字列も GROUP BY の基準にできる。日付から自作した「月」という切り口で、そのまま集計できる。
4実践シナリオ(5問)
1列7行。田中商事様 → ノートPC が先頭
3テーブルを結合し、c.name || '様 → ' || p.name のように連結する。
SELECT c.name || '様 → ' || p.name AS 明細 FROM orders o JOIN customers c ON o.customer_id = c.id JOIN products p ON o.product_id = p.id;
結合と文字列連結を組み合わせる。別々のテーブルにある値を、1つの読みやすい文章に組み立てられる。
2列2行。2026-01 349000 / 2026-02 183500
結合してから SUBSTR で月を作り GROUP BY。ORDER BY は月の文字列順でよい。
SELECT SUBSTR(o.order_date, 1, 7) AS 月, SUM(p.price * o.qty) AS 売上 FROM orders o JOIN products p ON o.product_id = p.id GROUP BY 月 ORDER BY 月;
月の文字列('2026-01'など)は、そのままORDER BYで正しい順序に並ぶ。ゼロ埋めされた日付形式の恩恵がここでも活きる。
2列3行。マウス 3 / モニター 4 / 新商品A 4
WHERE LENGTH(name) <= 4 と書く。
SELECT name, LENGTH(name) AS 文字数 FROM products WHERE LENGTH(name) <= 4;
LENGTH は WHERE の条件にも使える。入力チェックで「◯文字以上◯文字以下」を判定する処理は、この形が基本になる。
1行。1月:349,000円 / 2月:183,500円
サブクエリで各月の売上を計算し、文字列として連結する。3桁区切りは環境によるため、ここでは単純な数値でよい場合と桁区切りが必要な場合がある——今回は桁区切りなしで計算した値を文字列に変換して連結する。
SELECT
'1月:' || (
SELECT SUM(p.price * o.qty) FROM orders o
JOIN products p ON o.product_id = p.id
WHERE o.order_date LIKE '2026-01%'
) || '円 / 2月:' || (
SELECT SUM(p.price * o.qty) FROM orders o
JOIN products p ON o.product_id = p.id
WHERE o.order_date LIKE '2026-02%'
) || '円' AS 比較;
数値をそのまま || でつなぐと自動的に文字列へ変換される。サブクエリの結果を文字列に埋め込む——集計と文字列操作を組み合わせた応用形。
2列7行。新商品Aが 分類:未設定
CASE式(次章で本格的に扱う)か、COALESCEと||の組み合わせで作れる。COALESCE(category, '未設定') を使うと簡潔。
SELECT name, '分類:' || COALESCE(category, '未設定') AS 表示 FROM products;
COALESCEと文字列連結を組み合わせるのは実務で頻出のパターン。NULLの処理(SQL05)と文字列操作(本章)が、ここで初めて一緒に使われた。
5仕上げ課題
表示する列
① 年月(SUBSTR で先頭7文字)→ 別名「月」
② 注文件数 → 別名「件数」
③ 売上合計 → 別名「売上」
④ サマリー文(「2026年01月:3件・349000円」の形式。年月の "-" を "年" と "月" に置き換えること)→ 別名「サマリー」
並び順:月の順(古い順)
期待される結果(4列 × 2行)
月 | 件数 | 売上 | サマリー
2026-01 | 4 | 349000 | 2026年01月:4件・349000円
2026-02 | 3 | 183500 | 2026年02月:3件・183500円
ヒント:「2026-01」を「2026年01月」にするには、REPLACEを2回使うか、SUBSTRで年と月を別々に切り出して組み立てます。
4列 × 2行が完全一致
月は SUBSTR(order_date,1,7)。サマリー文は SUBSTR で年(4文字)と月(2文字)を別々に取り出し、'年' '月' ':' '件・' '円' を || でつなぐ。件数と売上はサブクエリではなく、同じ GROUP BY の中の集計関数を再利用できる。
SELECT
SUBSTR(o.order_date, 1, 7) AS 月,
COUNT(*) AS 件数,
SUM(p.price * o.qty) AS 売上,
SUBSTR(o.order_date, 1, 4) || '年' || SUBSTR(o.order_date, 6, 2) || '月:'
|| COUNT(*) || '件・' || SUM(p.price * o.qty) || '円' AS サマリー
FROM orders o
JOIN products p ON o.product_id = p.id
GROUP BY 月
ORDER BY 月;
集計関数を文字列の中で再利用できるのがこの課題の要点。COUNT(*) と SUM(p.price * o.qty) を、通常の列としても、サマリー文の材料としても、同じ GROUP BY の中で2度使っている。同じ計算を別々に書き直す必要はない。
そして SUBSTR(order_date, 1, 4)(年)と SUBSTR(order_date, 6, 2)(月)のように、1つの文字列から複数の部分を切り出して組み立て直す技法もここで身についた。開始位置を1つずつ数えれば、日付のどんな形式にも対応できる。
この章で学んだ文字列操作と日付操作は、単体では地味に見えるかもしれない。しかしJOIN・GROUP BY・COALESCE・サブクエリと組み合わさることで、初めて「読める報告書」になる。数字の羅列だったレポートに、人間が読む文章としての形が備わった。
次章では CASE 式を本格的に学ぶ。「条件によって表示を変える」という、S05で少し触れた技法を、本格的に使いこなせるようになる。