【決定版】主要データベースの型の違いまとめ|MySQL・PostgreSQL・SQLiteなどの違い

データベース・SQL

アプリ開発やデータ分析で避けて通れないのが「データベースの型(データ型)」です。

でも、同じ「文字列」や「日付」でも、使うデータベースによって型名が微妙に違うことに混乱した経験はありませんか?

たとえば:

  • VARCHAR?それともTEXT
  • DATETIMETIMESTAMPの違いって?
  • 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)
);

説明:同じ「文字列」でも、データベースによって推奨される型が異なります。

文字列型の違いを詳しく比較

文字列型の基本分類

固定長文字列

  • 常に決まった文字数で保存される
  • 短い文字列でも指定した長さ分のメモリを使う

可変長文字列

  • 実際の文字数に応じてメモリを使う
  • 一般的によく使われる

長文用文字列

  • 非常に長いテキストを保存できる
  • ブログ記事、説明文などに使用

データベース別文字列型比較

用途MySQLPostgreSQLSQLiteSQL Server
固定長(短い)CHAR(n)CHAR(n)TEXTCHAR(n)
可変長(一般的)VARCHAR(n)VARCHAR(n)TEXTVARCHAR(n)
可変長(日本語)VARCHAR(n)VARCHAR(n)TEXTNVARCHAR(n)
長文TEXTTEXTTEXTTEXT

実際の使用例

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などに使用

浮動小数点型

  • 小数点のある数値(近似値)
  • 科学計算、統計処理などに使用

固定小数点型

  • 小数点のある数値(正確な値)
  • 金額、重要な計算に使用

データベース別数値型比較

用途MySQLPostgreSQLSQLiteSQL Server
小さな整数TINYINTSMALLINTINTEGERTINYINT
一般的な整数INTINTEGERINTEGERINT
大きな整数BIGINTBIGINTINTEGERBIGINT
浮動小数点FLOAT, DOUBLEREAL, DOUBLE PRECISIONREALFLOAT, REAL
固定小数点DECIMAL(p,s)NUMERIC(p,s)NUMERICDECIMAL(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使用
);

数値型の使い分けガイド

用途推奨型理由
ユーザーIDINT または BIGINT整数で十分、高速
商品価格DECIMAL(10,2)金額は正確性が重要
統計データFLOAT または DOUBLE近似値で十分、計算が高速
在庫数INT整数で十分

日付・時刻型の違いを詳しく比較

日付・時刻型の基本分類

日付のみ

  • 年月日だけを保存
  • 例:2025-06-05

時刻のみ

  • 時分秒だけを保存
  • 例:14:30:25

日付時刻

  • 年月日と時分秒を両方保存
  • 例:2025-06-05 14:30:25

データベース別日付型比較

用途MySQLPostgreSQLSQLiteSQL Server
日付のみDATEDATETEXTDATE
時刻のみTIMETIMETEXTTIME
日付時刻DATETIMETIMESTAMPTEXTDATETIME
タイムゾーン付きTIMESTAMPTIMESTAMPTZDATETIMEOFFSET

実際の使用例

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)のどちらかの値を保存する型です。

使用例

  • ユーザーがアクティブかどうか
  • 商品が販売中かどうか
  • メール配信を希望するかどうか

データベース別論理型比較

データベース型名実際の保存形式使用可能な値
MySQLBOOLEANTINYINT(1)0, 1, TRUE, FALSE
PostgreSQLBOOLEAN専用の論理型TRUE, FALSE, NULL
SQLiteなしINTEGER0, 1
SQL ServerBITビット型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環境に適している

型選択の基本原則

  1. 目的に応じた適切な型を選ぶ
  2. 将来の拡張性を考慮する
  3. パフォーマンスを意識する
  4. チーム全体で統一ルールを決める

データベース別推奨用途

データベース推奨用途型の特徴
MySQLWebアプリ、中小規模システム標準的、使いやすい
PostgreSQLデータ分析、大規模システム豊富、厳密
SQLiteプロトタイプ、小規模アプリ柔軟、軽量
SQL Server企業システム、Windows環境高機能、統合性重視

コメント

タイトルとURLをコピーしました