順番に読み進めながら学べます

関数 ① — 算術演算・文字列連結・日付関数

SQL の関数記事 1 本目です。+ - * / % の算術演算、|| と CONCAT による文字列連結、現在日時の取得や年・月の抽出といった日付関数まで、CSV の社員データで動かしながら押さえます。

本記事で使うデータ — staff テーブル

ここから 3 本にわたって、SQL に組み込まれている 関数(function) を学びます。1 本目は 算術演算文字列連結日付関数 の 3 カテゴリで、いずれも SELECT の列リストで使うことが多い式です。

題材は CSV から自動ロードする staff テーブル(10 行: id / name / birthday / city / salary)です。salary を使った金額計算、name と city を使った文字列連結、birthday を使った日付フォーマットなど、本記事の 4 演習で多角的に使い分けます。

演習に入る前に、staff テーブルの 列定義データのサンプル を確認しておきます。

PRAGMA table_info(staff); で列名・型・主キーを確認してください。

SELECT * FROM staff LIMIT 5; で先頭 5 行のデータをプレビューしてください。

SQL エディタ

クエリを実行してください

算術演算子 — +, -, *, /, %

数値列を使った計算には + - * / % の 5 つの算術演算子が使えます。SQL は SELECT の列リストの中で式を書けるので、テーブルから取り出した値を その場で計算した結果 を別の列として返せます。また、AS 別名 で結果列に名前を付けると、画面表示や後段プログラムで扱いやすくなります。

割り算 /整数同士だと整数結果 になる DB(PostgreSQL / SQL Server など)と、自動的に小数になる DB(MySQL / 本講座のコンソール = SQLite)があります。

-- 1) テーブルを使わない単純な計算
SELECT 1 + 1;       -- 2
SELECT 10 - 3;      -- 7
SELECT 3 * 4;       -- 12
SELECT 10.0 / 3;    -- 3.333...
SELECT 10 % 3;      -- 1

-- 2) 列を使った計算(10 % 昇給後の年収)
SELECT name, salary, salary * 1.1 AS next_year_salary
FROM staff;

-- 3) 月給を計算(年俸 / 12)
SELECT name, salary / 12 AS monthly_salary FROM staff;
算術演算子の早見表
演算子意味+加算salary + 100000-減算salary - 100000*乗算salary * 1.1/除算salary / 12%剰余(割った余り)10 % 3 → 1
SQL に組み込まれている主要な算術演算子の一覧。+ - * / % の 5 つは、ほとんどのプログラミング言語と同じ意味で使えます。

次年度の昇給シミュレーションとして「全社員に 10% 昇給したときの年収」を表示したい、という要件を想定します。(正しく実行できれば解説が表示されます)

staff テーブルから namesalarysalary * 1.1next_year_salary という別名で、計 3 列を取り出してください。

next_year_salary の降順 で並べてください。

③ 結果が 10 行になり、先頭が Frank Tanaka 7,200,000 / 7,920,000 になることを確認してください。

SQL エディタ

クエリを実行してください

文字列連結 — `||` と `CONCAT()`

複数の文字列を 1 つにつなぐ操作を 連結 といいます。連結には書き方が 2 通りあり、本講座のコンソール (SQLite) と PostgreSQL / Oracle / SQL Server では `||`(縦棒 2 つ)演算子、MySQL では `CONCAT()` 関数を使います。SQLite は ||CONCAT()両方 をサポートするので、本記事は移植性の高い CONCAT() を中心に進めます。

途中に区切り文字(': '' / ')を挟むことで、namecity を「Alice Tanaka / Tokyo」のように見やすい 1 列にまとめられます。レポートや CSV 出力で「複数列を 1 列に結合した形でほしい」という場面で重宝する関数です。

-- 1) || 演算子(SQLite / PostgreSQL / Oracle)
SELECT name || ' (' || city || ')' AS label FROM staff;

-- 2) CONCAT 関数(MySQL / SQLite 3.40+ / PostgreSQL)
SELECT CONCAT(name, ' (', city, ')') AS label FROM staff;

-- どちらも結果は同じ
-- → Alice Tanaka (Tokyo) / Bob Suzuki (Osaka) / ...

`||` と `CONCAT()` のどちらを選ぶか

移植性で選ぶなら `CONCAT()` が安全です。SQLite / MySQL / PostgreSQL / SQL Server(2012+)/ Oracle のすべてで動きます。|| は SQL 標準ですが、MySQL では既定で論理 OR の意味になるため、本番が MySQL の可能性がある環境では CONCAT() を選ぶと書き換えなしで通用します。

NULL の扱いには差があり、NULL || 'A'|| だと NULL になります。一方 CONCAT(NULL, 'A') は MySQL では空文字を返し、PostgreSQL では NULL を返すなど挙動が分かれます。連結対象に NULL が混じる可能性があるときは、COALESCE(列, '') で NULL を空文字に変換してから連結するのが安全です(COALESCE は本連載 3 本目で扱います)。

社員カードの表示用に「名前のあとにスペース+丸括弧で勤務地」のラベル列を作りたい、という要件を想定します。

staff テーブルから namecity の元 2 列に加えて、`CONCAT(name, ' (', city, ')')` を `label` という別名で 取り出してください。

② 結果が 10 行になり、label 列に「Alice Tanaka (Tokyo)」「Bob Suzuki (Osaka)」のような形式で並ぶことを確認してください。

SQL エディタ

クエリを実行してください

日付関数 — 現在日時とフォーマット

「いま登録された日時を入れたい」「生年月日から年だけ取り出したい」のように、日付・時刻を扱うときに使うのが 日付関数 です。日付関数は DB ごとに名前と書き方が違う カテゴリの代表格で、本講座のコンソール (SQLite) と MySQL では呼び出し方がかなり違います。

本講座では SQLite の datetime('now') / date('now') / strftime('フォーマット', 値) を中心に演習し、MySQL の NOW() / CURDATE() / DATE_FORMAT(値, 'フォーマット') は対応表で並べて紹介します。フォーマット文字列('%Y' で年、'%m' で月、'%d' で日 など)は両 DB で共通の書式を使うので、書式部分だけは横展開できます。

-- 本講座のコンソール (SQLite) での書き方

-- 1) 現在日時 / 現在日付
SELECT datetime('now') AS current_dt, date('now') AS current_d;

-- 2) フォーマット指定(年だけ / 年月だけ)
SELECT strftime('%Y', '1990-04-15') AS year_only;       -- '1990'
SELECT strftime('%Y-%m', '1990-04-15') AS year_month;   -- '1990-04'

-- 3) 列に対するフォーマット
SELECT name, strftime('%Y', birthday) AS birth_year FROM staff;

-- 参考: MySQL で同じことを書く場合
--   SELECT NOW(), CURDATE();
--   SELECT DATE_FORMAT(birthday, '%Y') FROM staff;
用途本講座のコンソール (SQLite)MySQL
現在日時datetime('now')NOW()
現在日付date('now')CURDATE()
年だけ取り出すstrftime('%Y', d)DATE_FORMAT(d, '%Y')
フォーマット指定strftime('%Y-%m-%d', d)DATE_FORMAT(d, '%Y-%m-%d')

本講座のコンソールで 現在の日時現在の日付 を取り出して表示してみます。実行できれば OK です。

datetime('now')current_dt という別名で、date('now')current_d という別名で取り出してください。

② 結果として 1 行 2 列が表示され、current_dt に「YYYY-MM-DD HH:MM:SS」形式の現在時刻、current_d に「YYYY-MM-DD」形式の現在日付が入ることを確認してください。

SQL エディタ

クエリを実行してください

従業員一覧画面で「生まれ年」を別列で表示したい、という要件を想定します。

staff テーブルから namebirthday`strftime('%Y', birthday)` を `birth_year` という別名で、計 3 列を取り出してください。

② 結果が 10 行になり、Alice Tanaka なら birthday=1990-04-15birth_year='1990' のように、年だけが新しい列に入ることを確認してください。

SQL エディタ

クエリを実行してください

「1990 年代生まれの若手社員一覧を、生まれた順に表示したい」という要件を想定します。

staff テーブルから namebirthdaystrftime('%Y', birthday) AS birth_year の 3 列を取り出してください。

`birth_year` が `'1990'` 以上 `'1999'` 以下 に絞り込んでください(BETWEEN を使ってください)。

`birthday` の昇順(早く生まれた順)で並べ、先頭 3 行 に絞ってください。

④ 結果が 3 行(Alice 1990-04-15 / Grace 1991-05-25 / Carol 1992-11-03)になることを確認してください。

SQL エディタ

クエリを実行してください
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1次のうち、SELECT 10 % 3; の結果として正しいものはどれですか。

Q2本講座のコンソールで「namecityAlice Tanaka (Tokyo) のような形にまとめて 1 つの列で取り出す」書き方として正しいものはどれですか。

Q3本講座のコンソール (SQLite) で birthday 列から「年(4 桁)だけ」を取り出すときに使う書き方はどれですか。