404 Not Found

404 Not Found


nginx

MySQLのデータ型の詳細な解説と選択ガイド

データ型は、データの保存方法、占有する容量、およびそのデータに対して実行可能な操作を決定します。不適切なデータ型を選択すると、深刻な結果を招く可能性があります。

このレッスンでは、MySQLのすべてのデータ型と、それらを選択するための戦略について、体系的に解説します。

100%
graph TB
    A[MySQL Data Types] --> B[Integer Types]
    A --> C[Floating-point/Fixed-point type]
    A --> D[String Type]
    A --> E[Date and Time Type]
    A --> F[JSON Type]
    B --> B1[TINYINT]
    B --> B2[SMALLINT]
    B --> B3[INT]
    B --> B4[BIGINT]
    C --> C1[FLOAT]
    C --> C2[DOUBLE]
    C --> C3[DECIMAL]
    D --> D1[CHAR]
    D --> D2[VARCHAR]
    D --> D3[TEXT]
    D --> D4[ENUM]
    E --> E1[DATE]
    E --> E2[DATETIME]
    E --> E3[TIMESTAMP]

1. 学習内容


2. 精度に関する実話

(1) 課題:金額の計算に誤りがあった

あるECシステムでは、商品の価格はFLOAT型として保存されています:

SQL
-- Demonstration of Floating-Point Precision Loss
SELECT 0.1 + 0.2;  -- Results: 0.300000004(approximate value,Inaccurate)

-- It becomes more apparent after it is entered into the table
CREATE TABLE float_demo (price FLOAT);
INSERT INTO float_demo VALUES (199.99);
SELECT price FROM float_demo;  -- Results: 199.99(The display is correct, but there is a slight error in the internal storage.)
SELECT price + 0.01 FROM float_demo;  -- Cumulative errors may become apparent during calculations

1,000件の取引を経て、累積した精度誤差により、財務照合で数元の不一致が生じた。

(2) DECIMAL の解法

SQL
-- DECIMAL Precise Storage,No error
CREATE TABLE decimal_demo (price DECIMAL(10,2));
INSERT INTO decimal_demo VALUES (199.99);
SELECT price + 0.01 FROM decimal_demo;  -- Results: 200.00(Accurate)

結果:price = 200.00、誤りなく正確です。

タイプ 精度 適用シナリオ
FLOAT おおよその値(6~7桁) 科学計算;精度は不要
ダブル およその値 (15~16ビット) 科学計算
10進数 有効桁数 金額、財務データ

3. 整数型

バイト数 符号付き範囲 符号なし範囲
TINYINT 1 -128 ~ 127 0 ~ 255
SMALLINT 2 -32,768 ~ 32,767 0 ~ 65,535
MEDIUMINT 3 -8,388,608 ~ 8,388,607 0 ~ 16,777,215
入力 4 -2,147,483,648 ~ 2,147,483,647 0 ~ 4,294,967,295
BIGINT 8 -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 0 ~ 18,446,744,073,709,551,615

▶ 例:整数型

SQL
CREATE TABLE user_stats (
    id INT PRIMARY KEY AUTO_INCREMENT,
    age TINYINT UNSIGNED,              -- Age 0-255 Enough
    view_count INT UNSIGNED,           -- Number of views
    total_orders BIGINT UNSIGNED       -- Total Number of Orders(It's very likely)
);

-- UNSIGNED Indicates unsigned(Only positive numbers)
INSERT INTO user_stats (age, view_count, total_orders) 
VALUES (25, 1000000, 9999999999);
▶ 試してみよう
💡 ヒント: ストレージ容量を節約するために、要件を満たす最小のデータ型を選択してください。年齢には TINYINT を、ユーザー ID には BIGINT を使用してください。


4. 浮動小数点型と固定小数点型

バイト数 精度 用途
FLOAT 4 6~7桁 科学計算
ダブル 8 15~16ビット 科学計算
DECIMAL(M,D) 変数 正確 金額、金融

M = 桁数、D = 小数点以下の桁数。DECIMAL(10,2) は、最大 10 桁の整数 + 小数点以下 2 桁を表します。

▶ 例:DECIMAL の使用

SQL
CREATE TABLE financials (
    id INT PRIMARY KEY,
    amount DECIMAL(12,2),       -- Amount,Maximum 9999999999.99
    rate DECIMAL(5,4),          -- Ratio,Maximum 9.9999
    quantity DECIMAL(8,0)       -- Number of integers
);

INSERT INTO financials VALUES (1, 1234567.89, 0.0850, 1000);
SELECT * FROM financials;
▶ 試してみよう

出力:

TEXT
+----+-------------+--------+----------+
| id | amount      | rate   | quantity |
+----+-------------+--------+----------+
|  1 | 1234567.89  | 0.0850 |     1000 |
+----+-------------+--------+----------+

5. 文字列型

タイプ 最大長 機能 用途
CHAR(N) 255 バイト 固定長、高速 携帯電話番号、ID番号、MD5
VARCHAR(N) 65,535 バイト 可変長、省スペース ユーザー名、メールアドレス、役職
TINYTEXT 255 バイト テキスト 短いテキスト
テキスト 65,535 バイト テキスト 記事本文
MEDIUMTEXT 16M テキスト 長文記事
LONGTEXT 4G テキスト 超長文
ENUM 65,535 個の値 列挙型 ステータス、タイプ
セット 64 個の値 セット 複数選択ラベル

(1) CHAR 対 VARCHAR

SQL
-- CHAR(10) Fixed length, storing 'abc' uses 10 bytes
-- VARCHAR(10) Variable length, storing 'abc' uses 4 bytes (3 + 1 length prefix)

CREATE TABLE phones (
    -- Mobile Number (Fixed 11 digits), use CHAR for faster lookup
    mobile CHAR(11),
    -- Username length varies, use VARCHAR to save space
    username VARCHAR(50)
);

▶ 例:ENUM列挙型

SQL
CREATE TABLE orders (
    id INT PRIMARY KEY,
    status ENUM('pending', 'paid', 'shipped', 'completed', 'cancelled') DEFAULT 'pending'
);

INSERT INTO orders (id, status) VALUES (1, 'paid');
INSERT INTO orders (id) VALUES (2);  -- Default 'pending'

-- ENUM stores numerical indexes (1,2,3...), not strings
SELECT status, status + 0 AS index_num FROM orders;
▶ 試してみよう

出力:

TEXT
+---------+-----------+
| status  | index_num |
+---------+-----------+
| paid    |         2 |
| pending |         1 |
+---------+-----------+

6. 日付および時刻の型

タイプ 形式 範囲 バイト数
日付 YYYY-MM-DD 1000-01-01 ~ 9999-12-31 3
時間 HH:MM:SS -838:59:59 ~ 838:59:59 3
日時 YYYY-MM-DD HH:MM:SS 1000-01-01 ~ 9999-12-31 8
タイムスタンプ YYYY-MM-DD HH:MM:SS 1970-01-01 ~ 2038-01-19 4
YYYY 1901 ~ 2155 1

(1) DATETIME と TIMESTAMP の違い

ディメンション DATETIME TIMESTAMP
範囲 1000–9999 1970–2038
ストレージ 8バイト 4バイト
タイムゾーン 変換しない 自動的にUTCに変換
推奨事項 日付 レコードの作成・変更日時

▶ 例:日付と時刻の使用

SQL
CREATE TABLE events (
    id INT PRIMARY KEY AUTO_INCREMENT,
    event_name VARCHAR(100),
    event_date DATE,
    start_time TIME,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

INSERT INTO events (event_name, event_date, start_time) 
VALUES ('Tech Conference', '2026-09-15', '09:00:00');

SELECT * FROM events;
▶ 試してみよう

出力:

TEXT
+----+----------------+------------+------------+---------------------+---------------------+
| id | event_name     | event_date | start_time | created_at          | updated_at          |
+----+----------------+------------+------------+---------------------+---------------------+
|  1 | Tech Conference| 2026-09-15 | 09:00:00   | 2026-07-03 10:00:00 | 2026-07-03 10:00:00 |
+----+----------------+------------+------------+---------------------+---------------------+

7. JSON データ型 (MySQL 8.0 以降)

▶ 例:JSONの扱い方

SQL
CREATE TABLE products (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    attributes JSON
);

INSERT INTO products (name, attributes) VALUES 
('iPhone', '{"color": "black", "storage": 128, "tags": ["phone", "apple"]}');

-- Extract JSON value
SELECT 
    name,
    attributes->>'$.color' AS color,
    attributes->>'$.storage' AS storage
FROM products;

-- JSON Array Lookup
SELECT * FROM products WHERE JSON_CONTAINS(attributes->'$.tags', '"apple"');
▶ 試してみよう

出力:

TEXT
+--------+-------+---------+
| name   | color | storage |
+--------+-------+---------+
| iPhone | black | 128     |
+--------+-------+---------+

8. データ型の選択に関するベストプラクティス

シナリオ 推奨タイプ 理由
主キー ID BIGINT AUTO_INCREMENT 範囲が広く、パフォーマンスに優れる
ユーザー名 VARCHAR(50) 可変長、スペースを節約
メールアドレス VARCHAR(100) 可変長
電話番号 CHAR(11) 固定長、高速検索
パスワードハッシュ CHAR(60) bcryptは60文字に固定
金額 DECIMAL(10,2) 精密計算
ステータス ENUM または TINYINT 有限の選択肢
記事本文 テキスト 詳細テキスト
作成日時 TIMESTAMP 自動管理、4バイト
JSONデータ JSON インデックスと関数をサポート

❓ よくある質問

Q VARCHAR(255) と VARCHAR(256) の違いは何ですか?
A VARCHAR の長さが 255 以下の場合、長さの保存に 1 バイトが使用されます。長さが 255 を超える場合は、2 バイトが使用されます。パフォーマンス上の根本的な違いはありませんが、255 は一般的に用いられる区切り点となっています。
Q TIMESTAMP 2038 問題についてはどうすればよいですか?
A MySQL 8.0 ではすでに修正が予定されています。懸念がある場合は、代わりに DATETIME を使用してください。
Q 1つのフィールドに複数の値を格納することはできますか?
A SETデータ型やJSON配列を使用することは可能ですが、関連するテーブルに分割することをお勧めします(これがより標準的な手法です)。
Q TEXT フィールドにインデックスを設定できますか?
A はい、ただし作成できるのはプレフィックス・インデックスのみです (INDEX(col(100)))。フルインデックスが必要な場合は、VARCHAR の使用をご検討ください。

📖 まとめ


📝 練習問題

  1. 基本問題(難易度 ⭐):ECシステム用のproductsテーブルを設計し、商品名、価格、在庫数、ステータス、商品説明を格納するために適切なデータ型を選択してください。

  2. 上級演習(難易度 ⭐⭐)user_profiles という名前のテーブルを作成し、その中に JSON 型の preferences というフィールドを含め、JSON 値の抽出とクエリの実践を行ってください。

  3. 課題(難易度:⭐⭐⭐):金額を保存する際、DECIMAL(10,2)FLOATの精度の違いを比較し、実験を通じてDECIMALの正確性を実証してください。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%