アプリ開発やデータ分析で避けて通れないのが「データベースの型(データ型)」です。
でも、同じ「文字列」や「日付」でも、使うデータベースによって型名が微妙に違うことに混乱した経験はありませんか?
たとえば:
VARCHAR
?それともTEXT
?DATETIME
とTIMESTAMP
の違いって?- SQLiteには
BOOLEAN
がないって本当?
この記事では、MySQL・PostgreSQL・SQLite・SQL Serverなどの主要データベースにおける「型の違い」を、初心者にも分かりやすく比較・整理しました。
データベースの型とは?基本を理解しよう

データ型の基本概念
データ型とは、データベースに保存するデータの「種類」を決める仕組みです。
たとえば、「名前」は文字列、「年齢」は数値、「生年月日」は日付といった具合です。
身近な例で考えてみる
顧客情報テーブル
- 顧客ID:数値(例:1, 2, 3...)
- 名前:文字列(例:"田中太郎", "佐藤花子")
- 年齢:数値(例:25, 30, 35)
- 登録日:日付(例:2025-06-05)
- 有効フラグ:真偽値(例:true, false)
なぜデータ型が重要なの?
1. データの整合性を保つ
-- 年齢に文字列を入れようとするとエラー
INSERT INTO customers (age) VALUES ('二十五歳'); -- エラー!
INSERT INTO customers (age) VALUES (25); -- OK!
2. メモリ効率が良くなる
- 整数型:4バイト
- 文字列型:文字数 × 1〜4バイト
- 適切な型を選ぶことで、無駄なメモリ使用を避けられます
3. 処理速度が向上する
- 数値計算:数値型の方が高速
- 日付計算:日付型の方が正確で高速
データベースによる違いの例
同じ「顧客名」を格納する場合
-- MySQL
CREATE TABLE customers (
name VARCHAR(100)
);
-- PostgreSQL
CREATE TABLE customers (
name VARCHAR(100) -- または TEXT
);
-- SQLite
CREATE TABLE customers (
name TEXT
);
-- SQL Server
CREATE TABLE customers (
name NVARCHAR(100)
);
説明:同じ「文字列」でも、データベースによって推奨される型が異なります。
文字列型の違いを詳しく比較
文字列型の基本分類
固定長文字列
- 常に決まった文字数で保存される
- 短い文字列でも指定した長さ分のメモリを使う
可変長文字列
- 実際の文字数に応じてメモリを使う
- 一般的によく使われる
長文用文字列
- 非常に長いテキストを保存できる
- ブログ記事、説明文などに使用
データベース別文字列型比較
用途 | MySQL | PostgreSQL | SQLite | SQL Server |
---|---|---|---|---|
固定長(短い) | CHAR(n) | CHAR(n) | TEXT | CHAR(n) |
可変長(一般的) | VARCHAR(n) | VARCHAR(n) | TEXT | VARCHAR(n) |
可変長(日本語) | VARCHAR(n) | VARCHAR(n) | TEXT | NVARCHAR(n) |
長文 | TEXT | TEXT | TEXT | TEXT |
実際の使用例
MySQL
CREATE TABLE products (
code CHAR(10), -- 商品コード(固定10文字)
name VARCHAR(100), -- 商品名(最大100文字)
description TEXT -- 商品説明(長文)
);
PostgreSQL
CREATE TABLE products (
code CHAR(10), -- 商品コード
name VARCHAR(100), -- 商品名
description TEXT -- 商品説明(制限なし)
);
SQLite
CREATE TABLE products (
code TEXT, -- すべてTEXT
name TEXT, -- すべてTEXT
description TEXT -- すべてTEXT
);
SQL Server
CREATE TABLE products (
code CHAR(10), -- 商品コード
name NVARCHAR(100), -- 商品名(Unicode対応)
description NTEXT -- 商品説明(Unicode長文)
);
注意すべきポイント
SQLiteの特徴
-- SQLiteでは以下がすべて有効
INSERT INTO test_table VALUES ('文字列');
INSERT INTO test_table VALUES (123);
INSERT INTO test_table VALUES (12.34);
説明:SQLiteは型制約が緩く、同じカラムに異なる型のデータを入れられます。
SQL Serverの日本語対応
-- 日本語を正しく扱うには NVARCHAR を使用
CREATE TABLE users (
name NVARCHAR(50), -- Unicode対応(推奨)
name_old VARCHAR(50) -- ASCII文字のみ
);
数値型の違いを詳しく比較

数値型の基本分類
整数型
- 小数点のない数値
- 年齢、個数、IDなどに使用
浮動小数点型
- 小数点のある数値(近似値)
- 科学計算、統計処理などに使用
固定小数点型
- 小数点のある数値(正確な値)
- 金額、重要な計算に使用
データベース別数値型比較
用途 | MySQL | PostgreSQL | SQLite | SQL Server |
---|---|---|---|---|
小さな整数 | TINYINT | SMALLINT | INTEGER | TINYINT |
一般的な整数 | INT | INTEGER | INTEGER | INT |
大きな整数 | BIGINT | BIGINT | INTEGER | BIGINT |
浮動小数点 | FLOAT , DOUBLE | REAL , DOUBLE PRECISION | REAL | FLOAT , REAL |
固定小数点 | DECIMAL(p,s) | NUMERIC(p,s) | NUMERIC | DECIMAL(p,s) |
実際の使用例
商品情報テーブルの例
-- MySQL
CREATE TABLE products (
id INT AUTO_INCREMENT, -- 商品ID
price DECIMAL(10,2), -- 価格(例:12345.67)
weight FLOAT, -- 重量(例:1.23kg)
stock_count INT -- 在庫数
);
-- PostgreSQL
CREATE TABLE products (
id SERIAL, -- 自動増分ID
price NUMERIC(10,2), -- 価格
weight REAL, -- 重量
stock_count INTEGER -- 在庫数
);
-- SQLite
CREATE TABLE products (
id INTEGER PRIMARY KEY, -- 自動増分ID
price NUMERIC, -- 価格(制約緩い)
weight REAL, -- 重量
stock_count INTEGER -- 在庫数
);
精度の違いに注意
浮動小数点の問題
-- 浮動小数点は近似値のため、計算誤差が生じる
SELECT 0.1 + 0.2; -- 結果:0.30000000000000004(期待値:0.3)
固定小数点の正確性
-- DECIMALやNUMERICは正確な値を保持
CREATE TABLE financial (
amount DECIMAL(15,2) -- 金額は必ずDECIMAL使用
);
数値型の使い分けガイド
用途 | 推奨型 | 理由 |
---|---|---|
ユーザーID | INT または BIGINT | 整数で十分、高速 |
商品価格 | DECIMAL(10,2) | 金額は正確性が重要 |
統計データ | FLOAT または DOUBLE | 近似値で十分、計算が高速 |
在庫数 | INT | 整数で十分 |
日付・時刻型の違いを詳しく比較

日付・時刻型の基本分類
日付のみ
- 年月日だけを保存
- 例:2025-06-05
時刻のみ
- 時分秒だけを保存
- 例:14:30:25
日付時刻
- 年月日と時分秒を両方保存
- 例:2025-06-05 14:30:25
データベース別日付型比較
用途 | MySQL | PostgreSQL | SQLite | SQL Server |
---|---|---|---|---|
日付のみ | DATE | DATE | TEXT | DATE |
時刻のみ | TIME | TIME | TEXT | TIME |
日付時刻 | DATETIME | TIMESTAMP | TEXT | DATETIME |
タイムゾーン付き | TIMESTAMP | TIMESTAMPTZ | – | DATETIMEOFFSET |
実際の使用例
MySQL
CREATE TABLE events (
event_date DATE, -- 2025-06-05
event_time TIME, -- 14:30:25
created_at DATETIME, -- 2025-06-05 14:30:25
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
PostgreSQL
CREATE TABLE events (
event_date DATE, -- 2025-06-05
event_time TIME, -- 14:30:25
created_at TIMESTAMP, -- 2025-06-05 14:30:25
updated_at TIMESTAMPTZ DEFAULT NOW() -- タイムゾーン付き
);
SQLite
CREATE TABLE events (
event_date TEXT, -- '2025-06-05'
event_time TEXT, -- '14:30:25'
created_at TEXT, -- '2025-06-05 14:30:25'
updated_at TEXT DEFAULT (datetime('now'))
);
SQL Server
CREATE TABLE events (
event_date DATE, -- 2025-06-05
event_time TIME, -- 14:30:25
created_at DATETIME2, -- 高精度日時
updated_at DATETIMEOFFSET DEFAULT SYSDATETIMEOFFSET()
);
MySQLのDATETIMEとTIMESTAMPの違い
DATETIME
CREATE TABLE test_datetime (
created_at DATETIME
);
-- 常に入力された値がそのまま保存される
INSERT INTO test_datetime VALUES ('2025-06-05 14:30:25');
TIMESTAMP
CREATE TABLE test_timestamp (
created_at TIMESTAMP
);
-- タイムゾーンの影響を受ける
-- サーバーのタイムゾーン設定によって表示が変わる
SQLiteでの日付処理
日付の保存方法
-- 文字列として保存
INSERT INTO events (date_text) VALUES ('2025-06-05 14:30:25');
-- Unix時間として保存
INSERT INTO events (date_unix) VALUES (strftime('%s', 'now'));
-- Julianday として保存
INSERT INTO events (date_julian) VALUES (julianday('now'));
日付の計算
-- 1週間後の日付を計算
SELECT date('now', '+7 days');
-- 現在から3時間前
SELECT datetime('now', '-3 hours');
論理型(真偽値)の違いを詳しく比較
論理型とは?
**論理型(Boolean型)**は、真(true)または偽(false)のどちらかの値を保存する型です。
使用例
- ユーザーがアクティブかどうか
- 商品が販売中かどうか
- メール配信を希望するかどうか
データベース別論理型比較
データベース | 型名 | 実際の保存形式 | 使用可能な値 |
---|---|---|---|
MySQL | BOOLEAN | TINYINT(1) | 0 , 1 , TRUE , FALSE |
PostgreSQL | BOOLEAN | 専用の論理型 | TRUE , FALSE , NULL |
SQLite | なし | INTEGER | 0 , 1 |
SQL Server | BIT | ビット型 | 0 , 1 |
実際の使用例
MySQL
CREATE TABLE users (
id INT,
name VARCHAR(50),
is_active BOOLEAN DEFAULT TRUE,
email_opt_in BOOL DEFAULT FALSE
);
-- 値の挿入例
INSERT INTO users VALUES
(1, '田中', TRUE, FALSE),
(2, '佐藤', 1, 0), -- 数値でも可
(3, '鈴木', 'true', 'false'); -- 文字列でも可(自動変換)
PostgreSQL
CREATE TABLE users (
id INTEGER,
name VARCHAR(50),
is_active BOOLEAN DEFAULT TRUE
);
-- PostgreSQLでは厳密な論理値
INSERT INTO users VALUES
(1, '田中', TRUE),
(2, '佐藤', FALSE),
(3, '鈴木', NULL); -- NULLも可能
SQLite
CREATE TABLE users (
id INTEGER,
name TEXT,
is_active INTEGER CHECK(is_active IN (0, 1))
);
-- 0 または 1 で管理
INSERT INTO users VALUES
(1, '田中', 1), -- TRUE
(2, '佐藤', 0); -- FALSE
SQL Server
CREATE TABLE users (
id INT,
name NVARCHAR(50),
is_active BIT DEFAULT 1
);
-- BIT型は 0 または 1
INSERT INTO users VALUES
(1, '田中', 1),
(2, '佐藤', 0);
論理型の注意点
検索時の注意
-- MySQL:これらはすべて同じ意味
SELECT * FROM users WHERE is_active = TRUE;
SELECT * FROM users WHERE is_active = 1;
SELECT * FROM users WHERE is_active;
-- PostgreSQL:型が厳密
SELECT * FROM users WHERE is_active = TRUE; -- OK
SELECT * FROM users WHERE is_active = 1; -- エラーの場合あり
その他の重要な型とNULLの扱い

JSON型
PostgreSQL
CREATE TABLE products (
id INTEGER,
details JSON, -- JSON型
metadata JSONB -- バイナリJSON(高速)
);
-- JSON データの挿入
INSERT INTO products VALUES
(1, '{"name": "商品A", "price": 1000}', '{"tags": ["新商品", "人気"]}');
-- JSON データの検索
SELECT * FROM products WHERE details->>'name' = '商品A';
MySQL(5.7以降)
CREATE TABLE products (
id INT,
details JSON
);
-- JSON関数を使用
SELECT JSON_EXTRACT(details, '$.name') FROM products;
配列型(PostgreSQL)
CREATE TABLE tags (
id INTEGER,
tag_list TEXT[] -- 文字列配列
);
-- 配列データの挿入
INSERT INTO tags VALUES
(1, ARRAY['タグ1', 'タグ2', 'タグ3']),
(2, '{"タグA", "タグB"}');
-- 配列の検索
SELECT * FROM tags WHERE 'タグ1' = ANY(tag_list);
UUID型
PostgreSQL
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE users (
id UUID DEFAULT uuid_generate_v4(),
name VARCHAR(100)
);
MySQL
CREATE TABLE users (
id CHAR(36) DEFAULT (UUID()),
name VARCHAR(100)
);
NULLとデフォルト値の扱い
NULL の基本
-- NULL許可(デフォルト)
CREATE TABLE test (
name VARCHAR(50), -- NULLを許可
age INT NOT NULL, -- NULLを許可しない
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
デフォルト値の設定
-- MySQL
CREATE TABLE users (
status VARCHAR(20) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- PostgreSQL(関数も使用可能)
CREATE TABLE users (
id SERIAL,
status VARCHAR(20) DEFAULT 'active',
created_at TIMESTAMP DEFAULT NOW(),
random_id VARCHAR(10) DEFAULT substr(md5(random()::text), 1, 10)
);
型の選び方ガイドとベストプラクティス
基本的な型選択ルール
文字列の選び方
-- 固定長(郵便番号、商品コードなど)
postal_code CHAR(7), -- '1234567'
-- 短い可変長(名前、タイトルなど)
name VARCHAR(100), -- 制限があることを明示
-- 長文(説明、記事内容など)
description TEXT, -- 制限なし
数値の選び方
-- 整数(ID、個数など)
user_id INT, -- -2,147,483,648 ~ 2,147,483,647
product_count SMALLINT, -- -32,768 ~ 32,767
-- 金額(正確性が重要)
price DECIMAL(10,2), -- 99999999.99まで
-- 測定値(近似値で十分)
weight FLOAT, -- 重量、距離など
日付の選び方
-- 生年月日(時刻は不要)
birth_date DATE,
-- 作成日時(タイムゾーン重要)
created_at TIMESTAMP, -- または TIMESTAMPTZ
-- 営業時間(日付は不要)
open_time TIME,
パフォーマンスを考慮した型選択
インデックスと型の関係
-- 検索性能を重視する場合
CREATE TABLE users (
id INT PRIMARY KEY, -- 整数は高速
email VARCHAR(255), -- 適切な長さ制限
created_at TIMESTAMP, -- 範囲検索に最適
INDEX idx_email (email),
INDEX idx_created (created_at)
);
メモリ効率を考慮した設計
-- 良い例:必要最小限の型
CREATE TABLE products (
id INT, -- 4バイト
name VARCHAR(100), -- 実際の文字数分
price DECIMAL(8,2), -- 999999.99まで
is_active BOOLEAN -- 1バイト
);
-- 悪い例:過剰な型
CREATE TABLE products_bad (
id BIGINT, -- 8バイト(無駄)
name TEXT, -- 制限なし(メモリ無駄)
price DECIMAL(20,10), -- 過剰な精度
is_active VARCHAR(10) -- 'true'/'false' を文字列で
);
データベース選択のガイド
シンプルなアプリケーション
-- SQLite:設定が簡単、型制約が緩い
CREATE TABLE simple_app (
id INTEGER PRIMARY KEY,
data TEXT, -- なんでも保存可能
created_at TEXT -- 文字列で日付管理
);
Webアプリケーション
-- MySQL:バランスが良い、実績豊富
CREATE TABLE web_app (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200),
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
データ分析・複雑なクエリ
-- PostgreSQL:高機能、型が豊富
CREATE TABLE analytics (
id SERIAL PRIMARY KEY,
user_data JSONB, -- 構造化データ
tags TEXT[], -- 配列型
geo_point POINT, -- 地理座標
created_at TIMESTAMPTZ -- タイムゾーン付き
);
企業システム
-- SQL Server:Microsoft環境、高性能
CREATE TABLE enterprise (
id UNIQUEIDENTIFIER DEFAULT NEWID(),
data NVARCHAR(MAX), -- Unicode対応
created_at DATETIME2, -- 高精度時刻
rowversion ROWVERSION -- 楽観的ロック
);
実践的な移行・変換パターン

データベース間でのデータ移行
MySQL → PostgreSQL
-- MySQL
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
is_active BOOLEAN,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- PostgreSQL(対応版)
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
is_active BOOLEAN,
created_at TIMESTAMP DEFAULT NOW()
);
SQLite → MySQL
-- SQLite(柔軟)
CREATE TABLE flexible (
id INTEGER,
data TEXT, -- なんでも入る
numbers TEXT -- 数値も文字列
);
-- MySQL(厳密)
CREATE TABLE strict (
id INT,
data TEXT,
numbers DECIMAL(10,2), -- 数値として明確化
data_type ENUM('text', 'number', 'date') -- 型情報を明示
);
型変換の注意点
安全な型変換
-- 文字列→数値(エラーハンドリング)
-- MySQL
SELECT
name,
CASE
WHEN age REGEXP '^[0-9]+$' THEN CAST(age AS UNSIGNED)
ELSE NULL
END as age_number
FROM temp_table;
-- PostgreSQL
SELECT
name,
CASE
WHEN age ~ '^[0-9]+$' THEN age::INTEGER
ELSE NULL
END as age_number
FROM temp_table;
まとめ:適切なデータ型選択でより良いデータベース設計を!
重要なポイント
データベースごとの特徴
- MySQL:バランスが良く、Web開発に適している
- PostgreSQL:高機能で型が豊富、複雑なデータ処理に適している
- SQLite:軽量で設定が簡単、小規模アプリに適している
- SQL Server:企業システムに強く、Microsoft環境に適している
型選択の基本原則
- 目的に応じた適切な型を選ぶ
- 将来の拡張性を考慮する
- パフォーマンスを意識する
- チーム全体で統一ルールを決める
データベース別推奨用途
データベース | 推奨用途 | 型の特徴 |
---|---|---|
MySQL | Webアプリ、中小規模システム | 標準的、使いやすい |
PostgreSQL | データ分析、大規模システム | 豊富、厳密 |
SQLite | プロトタイプ、小規模アプリ | 柔軟、軽量 |
SQL Server | 企業システム、Windows環境 | 高機能、統合性重視 |
コメント