Q1次のうち、SELECT 10 % 3; の結果として正しいものはどれですか。
関数 ① — 算術演算・文字列連結・日付関数
SQL の関数記事 1 本目です。+ - * / % の算術演算、|| と CONCAT による文字列連結、現在日時の取得や年・月の抽出といった日付関数まで、CSV の社員データで動かしながら押さえます。
本記事で使うデータ — staff テーブル
ここから 3 本にわたって、SQL に組み込まれている 関数(function) を学びます。1 本目は 算術演算・文字列連結・日付関数 の 3 カテゴリで、いずれも SELECT の列リストで使うことが多い式です。
題材は CSV から自動ロードする staff テーブル(10 行: id / name / birthday / city / salary)です。salary を使った金額計算、name と city を使った文字列連結、birthday を使った日付フォーマットなど、本記事の 4 演習で多角的に使い分けます。
算術演算子 — +, -, *, /, %
数値列を使った計算には + - * / % の 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;
+ - * / % の 5 つは、ほとんどのプログラミング言語と同じ意味で使えます。文字列連結 — `||` と `CONCAT()`
複数の文字列を 1 つにつなぐ操作を 連結 といいます。連結には書き方が 2 通りあり、本講座のコンソール (SQLite) と PostgreSQL / Oracle / SQL Server では `||`(縦棒 2 つ)演算子、MySQL では `CONCAT()` 関数を使います。SQLite は || と CONCAT() の 両方 をサポートするので、本記事は移植性の高い CONCAT() を中心に進めます。
途中に区切り文字(': ' や ' / ')を挟むことで、name と city を「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 本目で扱います)。
日付関数 — 現在日時とフォーマット
「いま登録された日時を入れたい」「生年月日から年だけ取り出したい」のように、日付・時刻を扱うときに使うのが 日付関数 です。日付関数は 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') |
理解度チェック
まずは1問ずつ答えてみましょう。
Q2本講座のコンソールで「name と city を Alice Tanaka (Tokyo) のような形にまとめて 1 つの列で取り出す」書き方として正しいものはどれですか。
Q3本講座のコンソール (SQLite) で birthday 列から「年(4 桁)だけ」を取り出すときに使う書き方はどれですか。