データ型の基礎
概要
- 日程: Day 1 / セッション 5
- 時間: 11:40-12:00
- 形式: 座学
- ゴール: 数値型・文字列型・日付型・論理型それぞれの代表例と用途を区別できる
- 学習形式: 対話型解説
導入(5分)
前のセッションで \d employees を実行したとき、次のような表記が並んでいたはずです。
first_name | character varying(50)
salary | numeric(10,2)
hire_date | date
「VARCHAR(50)って何?」「NUMERIC(10, 2)って一体何の暗号?」と思った人、正解です。この20分でその暗号を解きます。
ここで少し考えてみてください。Excelでは1つのセルに「文字でも数字でも日付でも好きに入れられる」のが当たり前ですよね。でもRDBは違います。「この列には数値しか入れない」「この列には日付しか入れない」と、列ごとに型を厳密に決めます。なぜでしょう?
本編(15分)
1. なぜ型を決めるのか
データ型を決める理由はシンプルです。「データの嘘」を防ぐためです。
たとえば salary(給与)の列に「だいたい40万」と文字で書かれていたら、平均給与を計算できません。hire_date(入社日)に「去年の春くらい」と入っていたら、勤続年数を計算できません。
型は、いわばコップのサイズ表記のようなものです。「これは250ml用のコップ」と決めておけば、誰が見ても用途が分かり、お酒用とお茶用を混ぜずに済みます。
ここがポイント
- 型は「この列に入れていいデータの種類」を定めるルール
- ルールを破ろうとすると、PostgreSQLが「それはダメ」と即エラーで止めてくれる(事故防止)
2. 数値型——INTEGER, NUMERIC, SERIAL
サンドボックスでよく出てくる数値型は3つです。
| 型 | 用途 | 例 |
|---|---|---|
INTEGER |
整数(小数なし) | stock_quantity(在庫数)、quantity(注文数) |
NUMERIC(p, s) |
厳密な小数(pは全体桁数、sは小数桁数) | salary(給与)、price(価格)、unit_price |
SERIAL |
自動採番される整数(1, 2, 3, …) | employee_id、product_id などの主キー |
NUMERIC(10, 2) というのは、「全体で10桁、うち小数2桁」という意味です。つまり整数部分は8桁まで使えて、小数は2桁まで。給与なら最大 99,999,999.99 円まで表せる、というわけです。「お金を扱う列は NUMERIC が安全」と覚えてください。FLOAT や REAL などの近似値型は、誤差が出ることがあるので会計には向きません。
SERIAL は便利な仕組みで、INSERTのたびにPostgreSQLが自動で次の番号を振ってくれます。「主キーの値を毎回手で考えたくない」というニーズに応える発明品です。
コード例・実例
employees の定義(抜粋):
CREATE TABLE employees (
employee_id SERIAL PRIMARY KEY,
salary NUMERIC(10, 2),
...
);
employee_id は SERIAL なので、INSERTすると勝手に1, 2, 3, …と入ります。salary は NUMERIC(10, 2) なので、整数も小数も正確に扱えます。
3. 文字列型——VARCHAR と TEXT
文字を入れる列は、主に2種類です。
| 型 | 用途 | 例 |
|---|---|---|
VARCHAR(n) |
最大n文字までの可変長文字列 | first_name VARCHAR(50)、email VARCHAR(100) |
TEXT |
上限のない可変長文字列 | description TEXT(categoriesの説明) |
VARCHAR(100) は「最大100文字までの文字列」という意味です。101文字目を入れようとするとエラーになります。「上限を決めて事故を防ぐ」のが VARCHAR の役割です。
一方の TEXT は上限がありません。商品の説明や記事本文のように、長さが読めない列で使われます。
ここがポイント
VARCHAR(n)は「念のためこのくらいで切っとこう」という上限つき- 「メールアドレスは100文字まで」「氏名は50文字まで」のように、現実的な上限を決めるのが定石
- PostgreSQLの場合、VARCHARとTEXTのパフォーマンス差はほぼゼロ。「上限を持たせたいか」で選ぶ
コラム
VARCHAR の "VAR" は variable(可変の)の略です。実は VARCHAR には親戚の CHAR(n) という型があって、こちらは「常にn文字。短いときは半角スペースで埋める」という変わった性質を持っています。たとえば CHAR(10) で「太郎」を入れると、内部では「太郎 」(7文字分の空白付き)で保存されます。なぜそんな仕様があるかというと、コンピュータが貧弱だった時代に「固定長は速い」という事情があったからです。現代では特殊な事情がない限り VARCHAR か TEXT を使います。CHARを見かけたら「歴史を感じる古文書だな」と微笑んであげてください。
4. 日付・時刻型——DATE と TIMESTAMP
日付を扱う型も2種類押さえれば十分です。
| 型 | 用途 | 例 |
|---|---|---|
DATE |
日付のみ(年月日) | hire_date(入社日) |
TIMESTAMP |
日付+時刻(年月日時分秒) | order_date、created_at |
入社日のように「何月何日か」だけ知ればいい列は DATE、注文時刻のように「秒単位まで知りたい」列は TIMESTAMP を使います。
サンドボックスの orders では:
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
DEFAULT CURRENT_TIMESTAMP は「INSERT時に値を指定しなかったら、その瞬間の時刻を自動で入れる」という指定です。created_at(作成日時)にもよく使われる定番パターンです。
5. 論理型——BOOLEAN
サンドボックスでは直接出てきませんが、覚えておきたい型がもう1つ。
BOOLEAN:TRUE か FALSE の2値だけを取る型です。「公開中かどうか」「退職済みかどうか」のような Yes/No を表すのに使います。「退職済み?」を is_retired BOOLEAN という列で持つ、といった使い方です。
6. サンドボックスの型を読み解いてみる
ここまで来たら、employees の \d 出力を全部読めるはずです。
| カラム | 型 | 解釈 |
|---|---|---|
| employee_id | integer (SERIAL) | 自動採番される整数の主キー |
| first_name | varchar(50) | 最大50文字の文字列 |
| last_name | varchar(50) | 最大50文字の文字列 |
| varchar(100) | 最大100文字の文字列、UNIQUE | |
| hire_date | date | 日付(時刻なし) |
| salary | numeric(10,2) | 全体10桁・小数2桁の数値 |
| department_id | integer | 整数(departmentsへの外部キー) |
products や orders の \d も、今ならスラスラ読めます。
💬 AIに聞いてみよう
- 「VARCHARとTEXTを使い分ける基準を3つに整理して」
- 「給与をINTEGERで持つのとNUMERICで持つの、どっちがいい?それぞれの落とし穴は?」
- 「TIMESTAMP と TIMESTAMPTZ の違いって何?タイムゾーンが絡む話を教えて」
まとめ(5分)
今回学んだことを一言でまとめると「列ごとに型を厳しく決めることで、データの嘘を防ぎ、計算と検索を高速で正確にする」ということです。
代表選手は:
- 数値:
INTEGER、NUMERIC(p,s)、SERIAL - 文字:
VARCHAR(n)、TEXT - 日時:
DATE、TIMESTAMP - 真偽:
BOOLEAN
これだけ覚えれば、現場のテーブル定義の8割は読めます。
午前のセッションはここまで。昼休憩のあと、いよいよSELECT文の本格的な学びに入ります。今日見てきた departments、employees、products の型が、SQLでどう活きるかが見えてきます。
🔄 振り返りチェック
NUMERIC(10, 2)を自分の言葉で説明できますか?- VARCHARとTEXTの違い、DATEとTIMESTAMPの違いを2文ずつで説明できますか?
- なぜ給与は INTEGER ではなく NUMERIC を使うのが安全なのでしょうか?
補足資料
- 参考リンク: PostgreSQL公式: データ型
- 発展課題: products テーブルの
\dを実行し、各列の型がなぜその型で設計されているか(VARCHAR(100)、NUMERIC(10,2)、INTEGER、TIMESTAMP)を1つずつ説明してみる
学習ガイド
想定される質問と回答例
| 質問 | ヒント |
|---|---|
| INTEGER の上限は? | 約 ±21億(4バイト整数)。さらに大きい数を扱うなら BIGINT(8バイト整数)を使う |
| 小数を扱うのに FLOAT や REAL は使わないの? | 高速だが誤差が出る。金額には NUMERIC、物理量や統計量には FLOAT、と使い分ける |
| 日付フォーマットは何種類? | YYYY-MM-DD が標準。INSERT時もSELECT時もこの形が無難 |
| SERIAL と INTEGER の違いは? | SERIAL は実体としては INTEGER + 自動採番のシーケンス。データ自体は普通のINTEGERとして読み書きできる |
つまずきやすいポイント
| つまずきポイント | ヒント |
|---|---|
| VARCHAR(100) の「100」をバイト数だと思う | 文字数。日本語1文字も1とカウントされる(UTF-8の場合、内部バイト数は別の話) |
| NUMERIC(10, 2) の桁数を誤解する | 「全体10桁、うち小数2桁」。整数部分は最大8桁まで |
| DATEとTIMESTAMPを混在させる | 入社日はDATEで十分、注文日時はTIMESTAMP、と「秒単位の精度が必要か」で判断する |
| BOOLEANに0/1を入れたくなる | PostgreSQLは TRUE/FALSE(または 't'/'f')を使う。MySQL系の感覚と違うので注意 |