SQL / LESSON 12 / SQL12

SQL:文字列と日付の操作

1学習の目的

2基礎解説

やりたいこと書き方結果の例
連結するname || '(' || area || ')'田中商事(東京)
一部を切り出すSUBSTR(order_date, 1, 7)2026-01
文字数を調べるLENGTH(name)5
置き換えるREPLACE(name, 'PC', 'パソコン')ノートパソコン
✅ 覚えるべき重要ポイント
  1. 文字列の連結は ||(環境によっては CONCAT())。name || '(' || area || ')' のように、文字列と列を自由に組み合わせられる。
  2. SUBSTR(文字列, 開始位置, 長さ) で一部を切り出せる。開始位置は1から数える(0ではない)。SUBSTR('2026-01-05', 1, 4) なら年の4文字。
  3. 日付は文字列として保存されることが多い'2026-01-05' の形式)。年→月→日の順で書かれていれば、文字列としての大小比較がそのまま日付の前後関係と一致する。
  4. UPPER / LOWER は半角英数字にしか効かない。日本語の文字は変化しない。UPPER('ノートpc')'ノートPC' になるが、ひらがな・カタカナ・漢字はそのまま。
  5. 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問)

SQL12-D01 顧客名とエリアを「田中商事(東京)」の形式で連結し、label という別名で取り出すSQLを書け。 コーディング★☆☆無料
期待される結果

1列4行。田中商事(東京)が先頭

ヒント

|| で文字列と列をつなぐ。SELECT name || '(' || area || ')' AS label のように書く。

模範解答
SELECT name || '(' || area || ')' AS label
FROM customers;
解説

|| は文字列をつなげる演算子。列と固定の文字列を自由に組み合わせられるので、表示用の文字列を組み立てるときによく使う。

SQL12-D02 SUBSTR('2026-01-05', 1, 4) の結果はどれか。
A. "2026" B. "026-" C. "0-01" D. エラー
選択★☆☆無料
期待される結果

解答 == A

ヒント

1文字目から4文字ぶん切り出す。

模範解答
A
解説

開始位置は1から数える。0からではない点に注意。「1文字目から4文字」なので年の部分がちょうど取れる。

SQL12-D03 orders の order_date から年月部分(先頭7文字)を切り出し、order_date と年月(別名「年月」)を取り出すSQLを書け。 コーディング★☆☆無料
期待される結果

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」。年月だけを取り出すこの形は、月次集計の下準備として頻出する。

SQL12-D04 商品名の文字数を数えるSQLを完成させよ。 穴埋め★☆☆無料
コード
SELECT name, ____(name) AS 文字数
FROM products;
期待される結果

2列7行。ノートPC が 5

ヒント

「長さ」を意味する6文字の関数。

模範解答
LENGTH
解説

日本語も正しく1文字として数えられる(環境による)。「ノートPC」はノ・ー・ト・P・Cの5文字。

SQL12-D05 UPPER('ノートpc') の結果はどれか。
A. "ノートPC" B. "ノートpc"のまま C. 全角に変換される D. エラー
選択★☆☆無料
期待される結果

解答 == A

ヒント

UPPERが効くのは半角英字だけ。日本語部分はどうなるか。

模範解答
A
解説

半角の pc だけが PC に変わり、「ノート」の部分は変化しない。UPPER/LOWERは日本語には効かないので、全角文字を大文字化しようとしても無意味。

SQL12-D06 2026年2月の注文だけを取り出すSQLを書け(order_date が '2026-02' で始まるもの)。 コーディング★★☆無料
期待される結果

5列3行。id 5,6,7

ヒント

WHERE order_date LIKE '2026-02%' と書く。

模範解答
SELECT *
FROM orders
WHERE order_date LIKE '2026-02%';
解説

LIKE で前方一致にすれば「その月のすべて」が取れる。日付が文字列で保存されている前提の書き方。

SQL12-D07 2026年1月31日以前の注文を取り出すSQLを完成させよ。 穴埋め★★☆無料
コード
SELECT * FROM orders
WHERE order_date ____ '2026-01-31';
期待される結果

5列4行。1月の注文のみ

ヒント

「以下」を表す比較演算子。日付は文字列として大小比較できる。

模範解答
<=
解説

年→月→日の順で書かれた日付文字列は、そのまま大小比較が成立する。'2026-01-31' <= '2026-02-01' が正しく判定される。

SQL12-D08 日付が '2026-1-9'(月と日がゼロ埋めされていない)のように保存されていると、何が問題になるか。
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)で保存するのが鉄則。

SQL12-D09 商品名に含まれる "PC" を "パソコン" に置き換え、name と置換後の名前(別名「新名称」)を取り出すSQLを書け。 コーディング★★☆無料
期待される結果

2列7行。ノートPC → ノートパソコン

ヒント

REPLACE(name, 'PC', 'パソコン') と書く。

模範解答
SELECT name, REPLACE(name, 'PC', 'パソコン') AS 新名称
FROM products;
解説

該当しない行はそのまま返る。「マウス」には PC が含まれないので変化しない。REPLACEは表記ゆれの一括修正にも使われる。

SQL12-D10 月ごとの注文件数を、年月(別名「月」)と件数(別名「件数」)で取り出すSQLを書け。 コーディング★★☆無料
期待される結果

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問)

SQL12-S01 【注文明細の表示名】注文ごとに、「田中商事様 → ノートPC」の形式の表示名(別名「明細」)を、顧客名(c.name)・商品名(p.name)を結合して作るSQLを書け。 コーディング★★☆無料
期待される結果

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つの読みやすい文章に組み立てられる。

SQL12-S02 【月別売上レポート】月ごと(別名「月」)の売上合計(別名「売上」)を取り出し、月の順に並べるSQLを書け。 コーディング★★☆無料
期待される結果

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で正しい順序に並ぶ。ゼロ埋めされた日付形式の恩恵がここでも活きる。

SQL12-S03 【短い商品名の抽出】商品名の文字数が4文字以下の商品を、name と文字数(別名「文字数」)で取り出すSQLを書け。 コーディング★★☆無料
期待される結果

2列3行。マウス 3 / モニター 4 / 新商品A 4

ヒント

WHERE LENGTH(name) <= 4 と書く。

模範解答
SELECT name, LENGTH(name) AS 文字数
FROM products
WHERE LENGTH(name) <= 4;
解説

LENGTH は WHERE の条件にも使える。入力チェックで「◯文字以上◯文字以下」を判定する処理は、この形が基本になる。

SQL12-S04 【1月と2月の売上比較】月ごとの売上を1行に横並びで表示したい。「1月:349,000円 / 2月:183,500円」という1行の文字列(別名「比較」)を作るSQLを書け。 コーディング★★★無料
期待される結果

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 比較;
解説

数値をそのまま || でつなぐと自動的に文字列へ変換される。サブクエリの結果を文字列に埋め込む——集計と文字列操作を組み合わせた応用形。

SQL12-S05 【カテゴリ表記の統一】category が NULL の商品には "分類:未設定"、それ以外には "分類:" + カテゴリ名 という文字列(別名「表示」)を、name と並べて取り出すSQLを書け。 コーディング★★★無料
期待される結果

2列7行。新商品Aが 分類:未設定

ヒント

CASE式(次章で本格的に扱う)か、COALESCEと||の組み合わせで作れる。COALESCE(category, '未設定') を使うと簡潔。

模範解答
SELECT
  name,
  '分類:' || COALESCE(category, '未設定') AS 表示
FROM products;
解説

COALESCEと文字列連結を組み合わせるのは実務で頻出のパターン。NULLの処理(SQL05)と文字列操作(本章)が、ここで初めて一緒に使われた。

5仕上げ課題

SQL12-FINAL 【月次営業レポート】営業部から「月ごとの活動状況をテキストでまとめてほしい」と依頼された。

表示する列
① 年月(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で少し触れた技法を、本格的に使いこなせるようになる。