1. 数据类型分类

2. 数值类型
2.1 TINYINT类型------ 极小整数
文字描述
TINYINT占用1个字节,是最小的整数类型。默认有符号,范围从-128到127;如果设置为无符号(UNSIGNED),范围变为0到255。由于其存储空间小、查询效率高,适合存储状态码、年龄、数量等小范围数值。需要注意的是,MySQL中的BOOL和BOOLEAN类型实际上是TINYINT(1)的别名,使用0表示假,1表示真。
数值越界测试

实际案例
假设我们设计一个用户表,需要存储用户的年龄和在线状态:
sql
CREATE TABLE users (
user_id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
age TINYINT UNSIGNED,
is_online BOOL
);
-- 插入正常数据
INSERT INTO users (username, age, is_online) VALUES
('张三', 25, 1),
('李四', 30, 0);
-- 尝试插入超出范围的数据
INSERT INTO users (username, age) VALUES ('王五', 300);

其他类型可自己推导。
2.2 BIT ------ 位字段
BIT类型用于存储位字段值,语法为BIT(M),M表示位数,范围从1到64 。如果省略M,默认为1。BIT类型在存储开关状态、权限标记等场景非常高效。需要注意的是,直接查询BIT字段时,MySQL会按照ASCII码显示(MySQL 8.0.19之前 ),这可能看起来有些怪异,但实际上数据是正确存储的。新版本显示方式(MySQL 8.0.19+) 为显示十六进制。
sql
mysql> select * from tt2;
+------+------+
| id | a |
+------+------+
| 10 | | -- BIT值显示为空
| 65 | A | -- 65对应ASCII码的'A'
+------+------+

不同格式间转换
sql
create table bit_test( id int, b bit(8));
insert into bit_test values(1,65),(2,65),(3,10);
selct * from bit_test;
select id,b cast(b as unsigned) as decimal_value from bit_test;
select id,b, bin(b) as binary_value from bit_test;
select id,b,cast(char(b) as char) as ascii_char from bit_test;

实际案例
设计一个设备控制表,记录灯光和开关状态:
sql
CREATE TABLE device_control (
device_id INT,
light_switch BIT(1),
permission BIT(8)
);
-- 插入数据
INSERT INTO device_control VALUES
(1, 1, 65),
(2, 0, 255);
SELECT device_id, BIN(light_switch), BIN(permission) FROM device_control;
SELECT * FROM device_control WHERE (permission & 1) = 1;

如果我们有这样的值,只存放0或1,这时可以定义bit(1)。这样可以节省空间。

2.4 SMALLINT、MEDIUMINT、INT、BIGINT ------ 各类整数
MySQL提供了多种整数类型以适应不同范围的数值需求:
-
SMALLINT:2字节,范围-32768~32767。
-
MEDIUMINT:3字节,范围-8388608~8388607。
-
INT:4字节,范围-2147483648~2147483647。
-
BIGINT:8字节,范围-9223372036854775808~9223372036854775807。
选择原则很简单:根据实际数据范围选择最小的足够使用的类型,以节省存储空间。
实际案例
设计一个电商数据库,包含不同类型的数据:
sql
CREATE TABLE ecommerce_stats (
product_id INT, -- 商品ID,使用INT足够
daily_views SMALLINT UNSIGNED, -- 日浏览量,最大65535次
monthly_sales MEDIUMINT UNSIGNED, -- 月销量,最大1600多万
total_revenue BIGINT, -- 总收入,使用BIGINT防止溢出
warehouse_stock SMALLINT -- 库存,有符号可表示负库存(欠货)
);
INSERT INTO ecommerce_stats VALUES
(10001, 5230, 150000, 9999999999, 850),
(10002, 12000, 500000, -5000, -10); -- 负收入表示退款,负库存表示欠货
2.5 FLOAT ------ 单精度浮点数
FLOAT用于存储单精度浮点数,占用4个字节。语法为FLOAT(M,D),其中M表示总长度,D表示小数位数。例如FLOAT(5,2)表示总长5位,其中小数占2位,整数占3位,范围从-999.99到999.99。FLOAT适合存储对精度要求不高的数值,如平均分、温度等。需要注意的是,FLOAT在进行数值计算时可能会有精度损失。


实际案例
设计学生成绩表
sql
CREATE TABLE student_scores (
student_id INT,
course_name VARCHAR(50),
score FLOAT(5,2)
);
INSERT INTO student_scores VALUES
(1, '数学', 98.5),
(2, '数学', 76.345);
CREATE TABLE float_test (
value1 FLOAT(10,8),
value2 FLOAT(10,8)
);
INSERT INTO float_test VALUES (0.1, 0.2);
SELECT value1 + value2 FROM float_test;
-- 结果可能不是精确的0.3,而是0.30000000447034836

2.6 DOUBLE ------ 双精度浮点数
DOUBLE是双精度浮点数,占用8个字节,精度比FLOAT更高 。语法同样为DOUBLE(M,D)。DOUBLE适合存储科学计算、天文数据等对精度要求较高的场景,但仍然存在浮点数精度问题。如果需要精确计算,应该使用DECIMAL类型。
实际案例
存储天文观测数据和地理坐标:
sql
CREATE TABLE astronomical_data (
star_name VARCHAR(50),
distance DOUBLE(15,5), -- 距离,单位:光年,支持更大范围
right_ascension DOUBLE(10,8), -- 赤经,高精度
declination DOUBLE(10,8) -- 赤纬,高精度
);
INSERT INTO astronomical_data VALUES
('北极星', 433.8, 2.53018750, 89.26405556),
('天狼星', 8.6, 6.75247639, -16.71611667);
-- 地理坐标存储
CREATE TABLE gps_locations (
location_name VARCHAR(100),
latitude DOUBLE(10,8), -- 纬度,保留8位小数
longitude DOUBLE(11,8) -- 经度,保留8位小数
);
1.6 DECIMAL ------ 定点数
DECIMAL是定点数类型,语法为DECIMAL(M,D)。M是总位数(最大65),D是小数位数(最大30)。与浮点数不同,DECIMAL使用精确的十进制存储,不会有精度损失,特别适合存储货币、税率等需要精确计算的数值。虽然DECIMAL占用空间比FLOAT大,但在金融系统中不可或缺。
实际案例
设计银行账户系统
sql
CREATE TABLE bank_accounts (
account_id INT PRIMARY KEY,
customer_name VARCHAR(50),
balance DECIMAL(15,2),
interest_rate DECIMAL(5,4)
);
INSERT INTO bank_accounts VALUES
(1001, '张三', 9999999.99, 0.0350),
(1002, '李四', 0.01, 0.0250);
SELECT account_id,
balance * interest_rate AS yearly_interest FROM bank_accounts;

3. 字符串类型
字符串类型用于存储文本数据,MySQL提供了定长和变长两种主要字符串类型。
3.1 CHAR ------ 定长字符串
CHAR是定长字符串类型,语法为CHAR(M),M表示字符数,最大为255。无论实际存储的内容有多长,CHAR都会占用固定的M个字符的空间。如果存入的字符串长度小于M,MySQL会用空格填充到M长度;查询时会自动去除尾随空格。由于长度固定,CHAR的存取效率比VARCHAR高,适合存储长度固定的数据,如身份证号、手机号、MD5值等。


实际案例
设计身份证信息表:
sql
CREATE TABLE citizen_info (
id_card CHAR(18), -- 身份证号固定18位
name VARCHAR(50),
phone CHAR(11), -- 手机号固定11位
md5_password CHAR(32) -- MD5加密后固定32位
);
INSERT INTO citizen_info VALUES
('110101199001011234', '张三', '13800138000', MD5('123456')),
('110101199012122345', '李四', '13912345678', MD5('654321'));
-- 查询时自动去除空格
SELECT LENGTH(id_card), CHAR_LENGTH(id_card) FROM citizen_info;
-- 结果都是18,因为虽然存储时可能补空格,但查询时会去除
3.2 VARCHAR ------ 变长字符串
文字描述
VARCHAR是变长字符串类型,语法为VARCHAR(M),M表示最大字符数,最大可达65535字节。VARCHAR根据实际存储的内容动态分配空间,比CHAR节省存储空间,但存取效率稍低。VARCHAR需要额外的1-3字节记录字符串长度。VARCHAR的M上限与字符编码密切相关:UTF8编码下,每个字符占3字节,所以最大字符数为65532/3≈21844;GBK编码下每个字符占2字节,最大字符数为65532/2=32766。
实际案例
3.2.1 CHAR和VARCHAR的对比与选择
CHAR和VARCHAR的选择需要权衡存储空间和查询效率:
| 特性 | CHAR | VARCHAR |
|---|---|---|
| 长度特性 | 固定长度 | 可变长度 |
| 存储空间 | 总是分配最大长度 | 按实际长度分配,加1-3字节长度信息 |
| 查询效率 | 高 | 稍低 |
| 适用场景 | 长度固定的数据 | 长度变化大的数据 |
实际案例
通过对比展示两者的存储差异:
sql
CREATE TABLE char_vs_varchar (
fixed CHAR(10),
variable VARCHAR(10)
);
INSERT INTO char_vs_varchar VALUES
('abc', 'abc'),
('abcdefgh', 'abcdefgh');
SELECT
fixed,
LENGTH(fixed) AS fixed_len,
variable,
LENGTH(variable) AS var_len
FROM char_vs_varchar;

3.3 TEXT和BLOB ------ 大文本和二进制数据
文字描述
TEXT和BLOB用于存储大量数据:
-
TEXT:存储大文本数据,有字符集概念,适合存储文章、日志等。
-
BLOB:存储二进制数据,无字符集概念,适合存储图片、文件等。
MySQL提供了四种TEXT/BLOB类型,区别在于最大长度:
-
TINYTEXT/TINYBLOB:最大255字节。
-
TEXT/BLOB:最大65535字节(64KB)。
-
MEDIUMTEXT/MEDIUMBLOB:最大16777215字节(16MB)。
-
LONGTEXT/LONGBLOB:最大4294967295字节(4GB)。
需要注意的是,TEXT/BLOB类型不支持默认值,且在使用时需要注意性能影响。
实际案例
设计博客系统和文件存储系统:
sql
-- 博客文章表
CREATE TABLE blog_posts (
post_id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200),
content TEXT, -- 文章内容
excerpt TINYTEXT, -- 文章摘要
full_content LONGTEXT, -- 如果文章特别长
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO blog_posts (title, content, excerpt) VALUES
('MySQL数据类型详解',
'这是一篇关于MySQL数据类型的详细介绍文章,内容非常丰富...(此处省略5000字)',
'本文详细介绍MySQL的各种数据类型及其使用场景'),
('数据库设计最佳实践',
'在设计数据库时,我们需要考虑...(此处省略3000字)',
'数据库设计的原则和技巧');
-- 文件存储系统
CREATE TABLE file_storage (
file_id INT PRIMARY KEY AUTO_INCREMENT,
file_name VARCHAR(255),
file_size INT,
file_data LONGBLOB, -- 存储文件二进制数据
file_type VARCHAR(50),
upload_time DATETIME
);
-- 存储图片文件(示例中使用LOAD_FILE函数)
INSERT INTO file_storage (file_name, file_size, file_data, file_type)
VALUES
('profile.jpg', 102400, LOAD_FILE('/tmp/profile.jpg'), 'image/jpeg'),
('document.pdf', 2048000, LOAD_FILE('/tmp/document.pdf'), 'application/pdf');
-- 注意事项:TEXT类型不能有默认值
CREATE TABLE text_with_default (
content TEXT DEFAULT '默认内容' -- 这会报错
); -- 错误:TEXT类型不能有默认值
-- 正确做法
CREATE TABLE text_with_default (
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
4、日期和时间类型
MySQL提供了多种日期时间类型,以满足不同精度和范围的需求。
4.1 DATE ------ 日期类型
文字描述
DATE类型用于存储日期值,格式为'YYYY-MM-DD',范围从**'1000-01-01'到'9999-12-31',**占用3个字节。DATE类型只存储日期,不包含时间部分,适合存储生日、纪念日、入职日期等只需要日期的场景。MySQL会自动验证日期的有效性,比如不会接受'2024-02-30'这样的无效日期。
实际案例
设计员工管理系统和节日表:
sql
-- 员工信息表
CREATE TABLE employees (
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(50),
birth_date DATE, -- 出生日期
hire_date DATE, -- 入职日期
termination_date DATE -- 离职日期(可为空)
);
INSERT INTO employees (emp_name, birth_date, hire_date) VALUES
('张三', '1995-07-15', '2020-03-01'),
('李四', '1988-12-25', '2019-06-15'),
('王五', '2000-02-29', '2023-01-10'); -- 闰年日期有效
-- 查询今天过生日的员工
SELECT * FROM employees
WHERE MONTH(birth_date) = MONTH(CURDATE())
AND DAY(birth_date) = DAY(CURDATE());
-- 查询入职满5年的员工
SELECT * FROM employees
WHERE hire_date <= DATE_SUB(CURDATE(), INTERVAL 5 YEAR);
-- 节日表
CREATE TABLE holidays (
holiday_name VARCHAR(50),
holiday_date DATE,
is_annual BOOLEAN DEFAULT TRUE -- 是否每年重复
);
INSERT INTO holidays VALUES
('元旦', '2024-01-01', TRUE),
('春节', '2024-02-10', FALSE), -- 春节日期每年变化
('国庆节', '2024-10-01', TRUE);
4.2 DATETIME ------ 日期和时间
文字描述
DATETIME类型同时存储日期和时间,格式为'YYYY-MM-DD HH:MM:SS',范围从'1000-01-01 **00:00:00'到'9999-12-31 23:59:59',**占用8个字节。DATETIME不受时区影响,适合存储需要精确到秒的时间点,如订单创建时间、日志记录时间、活动开始结束时间等。
实际案例
设计订单系统和活动管理系统:
sql
-- 订单表
CREATE TABLE orders (
order_id INT PRIMARY KEY AUTO_INCREMENT,
customer_id INT,
order_time DATETIME, -- 下单时间
payment_time DATETIME, -- 支付时间
delivery_time DATETIME, -- 发货时间
completion_time DATETIME, -- 完成时间
status VARCHAR(20)
);
INSERT INTO orders (customer_id, order_time, status) VALUES
(1001, '2024-03-20 10:30:25', '待付款'),
(1002, '2024-03-20 14:45:10', '已付款');
-- 更新支付时间
UPDATE orders
SET payment_time = '2024-03-20 10:35:18', status = '已付款'
WHERE order_id = 1;
-- 查询今天的所有订单
SELECT * FROM orders
WHERE DATE(order_time) = CURDATE();
-- 查询最近一小时的订单
SELECT * FROM orders
WHERE order_time >= NOW() - INTERVAL 1 HOUR;
sql
-- 活动管理表
CREATE TABLE events (
event_id INT PRIMARY KEY AUTO_INCREMENT,
event_name VARCHAR(100),
start_time DATETIME,
end_time DATETIME,
location VARCHAR(200)
);
INSERT INTO events VALUES
(1, 'MySQL技术交流会', '2024-04-15 14:00:00', '2024-04-15 17:30:00', '北京会议中心'),
(2, '数据库设计培训', '2024-05-20 09:00:00', '2024-05-22 18:00:00', '上海培训中心');
-- 查询当前正在进行的活动
SELECT * FROM events
WHERE NOW() BETWEEN start_time AND end_time;
4.3 TIMESTAMP ------ 时间戳
文字描述
TIMESTAMP类型也存储日期和时间,格式同DATETIME,但范围较小,从'1970-01-01 00:00:01' UTC到'2038-01-19 03:14:07' UTC,占用4个字节。TIMESTAMP的特点是:
-
自动时区转换:存储时转换为UTC,查询时转换为当前时区。
-
自动更新:可以设置自动初始化和自动更新。
-
适合记录数据的创建和修改时间。
实际案例


5、枚举和集合类型
枚举和集合是MySQL提供的特殊字符串类型,用于限制字段的取值范围。
5.1 ENUM ------ 枚举类型(单选)
ENUM是枚举类型,语法为ENUM('值1','值2','值3',...),最多可以定义65535个枚举值。ENUM在存储时实际存储的是整数值(从1开始),而不是字符串本身,这样可以节省存储空间。ENUM适合存储固定选项的单选字段,如性别、状态、级别等。使用ENUM可以确保数据的完整性和一致性。
5.2 SET ------ 集合类型(多选)
SET是集合类型,语法为SET('值1','值2','值3',...),最多可以定义64个成员。SET允许从定义的列表中选择多个值,用逗号分隔。存储时,SET使用位掩码的方式存储(每个值对应一个位:1,2,4,8,16...),这样可以极大节省存储空间。SET适合存储多选项字段,如兴趣爱好、特长、权限等。
有一个调查表votes,需要调查人的喜好, 比如(登山,游泳,篮球,武术)中去选择(可以多选), (男,女)[单选]


5.3 ENUM和SET的高级查询技巧
使用ENUM和SET时,掌握一些高级查询技巧可以更高效地处理数据。特别是SET类型,由于其位存储的特性,可以使用位运算进行复杂的查询。
实际案例
演示ENUM和SET的高级查询:
sql
-- 创建一个完整的调查表
CREATE TABLE survey_responses (
response_id INT PRIMARY KEY AUTO_INCREMENT,
respondent_name VARCHAR(50),
gender ENUM('男', '女', '其他') NOT NULL,
age_group ENUM('18-25', '26-35', '36-50', '50+') NOT NULL,
interests SET('科技', '时尚', '体育', '财经', '教育', '旅游', '健康', '娱乐') NOT NULL,
satisfaction ENUM('非常满意', '满意', '一般', '不满意', '非常不满意') DEFAULT '一般',
submit_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入示例数据
INSERT INTO survey_responses (respondent_name, gender, age_group, interests, satisfaction) VALUES
('张三', '男', '26-35', '科技,体育,财经', '满意'),
('李四', '女', '18-25', '时尚,旅游,娱乐', '非常满意'),
('王五', '男', '36-50', '科技,财经,健康', '一般'),
('赵六', '女', '26-35', '时尚,教育,旅游', '满意'),
('孙七', '其他', '18-25', '娱乐,科技', '非常满意');






