MySQL数据类型详解

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', '娱乐,科技', '非常满意');

相关推荐
阿贵---2 小时前
使用Fabric自动化你的部署流程
jvm·数据库·python
fy121632 小时前
MySQL篇(管理工具)
数据库·mysql
SelectDB2 小时前
PostgreSQL + Apache Doris:构建用于实时分析的 HTAP 架构
大数据·数据库·数据分析
Riden刘2 小时前
SQL里怎么存变量?怎么优雅处理递归?不妨了解下CTE!
数据库·sql
2401_873204652 小时前
使用Scrapy框架构建分布式爬虫
jvm·数据库·python
阿蒙Amon2 小时前
C#常用类库-详解JetBrains.Annotations
前端·数据库·c#
m0_716667072 小时前
工具、测试与部署
jvm·数据库·python
2501_945424802 小时前
构建一个基于命令行的待办事项应用
jvm·数据库·python
内网渗透2 小时前
Komari 部署教程:无数据库、单文件、Docker 一键启动的监控工具
数据库·docker·容器·内网穿透·cpolar·远程办公·komari