数据库-数据类型,表的约束和基本查询操作
一、数值类型
1. 整数类型
类型 | 字节 | 有符号范围 | 无符号范围 | 操作注意事项 |
---|---|---|---|---|
TINYINT | 1 | -128 ~ 127 | 0 ~ 255 | 默认有符号,UNSIGNED 定义无符号 |
SMALLINT | 2 | -32768 ~ 32767 | 0 ~ 65535 | 无符号需显式声明 |
INT | 4 | -2^31 ~ 2^31-1 | 0 ~ 2^32-1 | 推荐优先使用INT |
BIGINT | 8 | -2^63 ~ 2^63-1 | 0 ~ 2^64-1 | 存储超长整数时使用 |
示例:
CREATE TABLE tt2(num TINYINT UNSIGNED); -- 无符号TINYINT
INSERT INTO tt2 VALUES(255); -- 有效
INSERT INTO tt2 VALUES(-1); -- 报错:越界
2. 小数类型
类型 | 特点 | 语法示例 | 精度对比 |
---|---|---|---|
FLOAT | 单精度,约7位有效数字 | FLOAT(M, D) | 快速计算但精度低 |
DOUBLE | 双精度,约15位有效数字 | DOUBLE(M, D) | 精度高于FLOAT |
DECIMAL | 精确小数,高精度计算 | DECIMAL(M, D) | 精确存储(如金额) |
示例:
CREATE TABLE tt8 (salary FLOAT(10,8), salary2 DECIMAL(10,8));
INSERT INTO tt8 VALUES(23.12345612, 23.12345612);
SELECT * FROM tt8;
-- 结果:FLOAT显示23.12345695,DECIMAL显示23.12345612(精度更高)
3. BIT类型
- 语法:
BIT(M)
,M范围1~64,默认1。 - 显示规则:按ASCII码显示。
- 适用场景:存储二进制标志(如性别0/1)。
示例:
CREATE TABLE tt5(gender BIT(1)); -- 存储0或1
INSERT INTO tt5 VALUES(0), (1); -- 有效
INSERT INTO tt5 VALUES(2); -- 报错:越界
二、字符串类型
1. CHAR与VARCHAR对比
类型 | 特点 | 最大长度 | 存储方式 | 适用场景 |
---|---|---|---|---|
CHAR | 定长,固定占用空间 | 255字符 | 预先分配空间 | 身份证、MD5值 |
VARCHAR | 变长,按需分配空间 | 65535字节 | 动态分配空间 | 姓名、地址 |
示例:
CREATE TABLE tt10(name VARCHAR(6) CHARSET=utf8); -- UTF8下最大21844字符
INSERT INTO tt10 VALUES('我爱你,中国'); -- 6个字符(UTF8每个汉字3字节)
2. BLOB与TEXT
- BLOB:存储二进制数据(如图片、文件)。
- TEXT:存储大文本,不支持全文索引和默认值。
三、时间日期类型
类型 | 格式 | 范围 | 占用空间 | 特点 |
---|---|---|---|---|
DATE | YYYY-MM-DD | 1000-01-01 ~ 9999-12-31 | 3字节 | 仅日期 |
DATETIME | YYYY-MM-DD HH:MM:SS | 1000-01-01 ~ 9999-12-31 | 8字节 | 日期+时间 |
TIMESTAMP | YYYY-MM-DD HH:MM:SS | 1970-01-01 ~ 2038-01-19 | 4字节 | 自动更新为当前时间 |
示例:
CREATE TABLE birthday (t1 DATE, t2 DATETIME, t3 TIMESTAMP);
INSERT INTO birthday(t1,t2) VALUES('2000-01-01', '2023-10-01 12:00:00');
UPDATE birthday SET t1='2005-05-05'; -- t3自动更新为当前时间
四、ENUM与SET类型
1. ENUM(单选)
- 语法:
ENUM('选项1', '选项2', ...)
,存储对应数字(1,2,…)。 - 示例:
CREATE TABLE votes(gender ENUM('男','女')); INSERT INTO votes VALUES('男'), (2); -- 2对应'女'
2. SET(多选)
- 语法:
SET('选项1', '选项2', ...)
,存储对应数字(1,2,4,8,…)。 - 查询:使用
FIND_IN_SET
函数。CREATE TABLE votes(hobby SET('登山','游泳','篮球')); INSERT INTO votes VALUES('登山,游泳'); SELECT * FROM votes WHERE FIND_IN_SET('登山', hobby); -- 查询包含"登山"的记录
五、关键注意事项
- 数值类型选择:
- 优先使用
DECIMAL
存储精确小数(如金额)。 - 避免使用
UNSIGNED
,直接升级类型(如INT
→BIGINT
)更安全。
- 优先使用
- 字符串类型优化:
CHAR
适合定长数据(如手机号),VARCHAR
适合变长数据(如地址)。
- 时间类型自动更新:
TIMESTAMP
字段在数据更新时会自动刷新为当前时间。
- ENUM/SET查询技巧:
- 避免直接使用数字插入,优先用可读字符串。
一、约束类型概览
约束类型 | 作用 | 关键字 | 特点 |
---|---|---|---|
空属性约束 | 控制字段是否允许为NULL | NOT NULL | 强制字段必须有值 |
默认值约束 | 指定字段的默认值 | DEFAULT | 插入数据时可选使用默认值 |
列描述约束 | 为字段添加注释 | COMMENT | 仅描述作用,不影响数据 |
零填充约束 | 数字显示时自动填充前导零 | ZEROFILL | 仅影响显示,不改变存储值 |
主键约束 | 唯一标识表中的记录 | PRIMARY KEY | 唯一、非空,一张表只能有一个 |
自增长约束 | 自动生成递增的整数值 | AUTO_INCREMENT | 需与主键/唯一键搭配使用 |
唯一键约束 | 确保字段值唯一(允许NULL) | UNIQUE KEY | 可多个,NULL不参与唯一性检查 |
外键约束 | 强制关联主表的主键或唯一键 | FOREIGN KEY | 维护表间数据一致性 |
二、核心约束详解
1. 空属性约束(NOT NULL)
- 语法:
CREATE TABLE 表名 (字段名 数据类型 NOT NULL);
- 示例:
CREATE TABLE myclass (class_name VARCHAR(20) NOT NULL,class_room VARCHAR(10) NOT NULL );
- 操作细节:
- 插入数据时,若未给
NOT NULL
字段赋值,会报错:ERROR 1364 (HY000): Field 'class_room' doesn't have a default value
- 插入数据时,若未给
2. 默认值约束(DEFAULT)
- 语法:
CREATE TABLE 表名 (字段名 数据类型 DEFAULT 默认值);
- 示例:
CREATE TABLE tt10 (name VARCHAR(20) NOT NULL,age TINYINT UNSIGNED DEFAULT 0,sex CHAR(2) DEFAULT '男' );
- 操作细节:
- 插入时省略字段,自动填充默认值:
INSERT INTO tt10(name) VALUES('张三'); -- age=0, sex='男'
- 插入时省略字段,自动填充默认值:
3. 列描述约束(COMMENT)
- 语法:
CREATE TABLE 表名 (字段名 数据类型 COMMENT '注释内容');
- 查看注释:
SHOW CREATE TABLE 表名\G
4. 零填充约束(ZEROFILL)
- 语法:
CREATE TABLE 表名 (字段名 INT(显示长度) ZEROFILL);
- 示例:
ALTER TABLE tt3 CHANGE a a INT(5) UNSIGNED ZEROFILL;
- 效果:
- 存储值
1
→ 显示为00001
,实际存储仍为1
。
- 存储值
5. 主键约束(PRIMARY KEY)
- 语法:
-- 单字段主键 CREATE TABLE 表名 (字段名 数据类型 PRIMARY KEY);-- 复合主键 CREATE TABLE 表名 (字段1 数据类型, 字段2 数据类型, PRIMARY KEY(字段1, 字段2));
- 示例:
CREATE TABLE tt14 (id INT UNSIGNED,course CHAR(10),PRIMARY KEY(id, course) -- 复合主键 );
- 操作细节:
- 插入重复主键报错:
ERROR 1062 (23000): Duplicate entry '1-123' for key 'PRIMARY'
- 删除主键:
ALTER TABLE 表名 DROP PRIMARY KEY;
- 插入重复主键报错:
6. 自增长约束(AUTO_INCREMENT)
- 语法:
CREATE TABLE 表名 (字段名 INT PRIMARY KEY AUTO_INCREMENT);
- 示例:
CREATE TABLE tt21 (id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,name VARCHAR(10) NOT NULL DEFAULT '' );
- 操作细节:
- 插入时省略自增长字段,自动生成递增值:
INSERT INTO tt21(name) VALUES('a'); -- id=1 INSERT INTO tt21(name) VALUES('b'); -- id=2
- 获取最后插入的ID:
SELECT LAST_INSERT_ID();
- 插入时省略自增长字段,自动生成递增值:
7. 唯一键约束(UNIQUE KEY)
- 语法:
CREATE TABLE 表名 (字段名 数据类型 UNIQUE KEY);
- 示例:
CREATE TABLE student (id CHAR(10) UNIQUE COMMENT '学号',name VARCHAR(10) );
- 操作细节:
- 允许插入多个
NULL
值,但非NULL
值必须唯一:INSERT INTO student VALUES(NULL, '张三'); -- 允许 INSERT INTO student VALUES('001', '李四'); -- 重复则报错
- 允许插入多个
8. 外键约束(FOREIGN KEY)
- 语法:
CREATE TABLE 从表名 (字段名 数据类型,FOREIGN KEY (从表字段) REFERENCES 主表名(主表字段) );
- 示例:
-- 主表 CREATE TABLE myclass (id INT PRIMARY KEY, name VARCHAR(30) NOT NULL);-- 从表 CREATE TABLE stu (id INT PRIMARY KEY,class_id INT,FOREIGN KEY (class_id) REFERENCES myclass(id) );
- 操作细节:
- 插入无效外键值报错:
ERROR 1452 (23000): Cannot add or update a child row
- 允许外键为NULL:
INSERT INTO stu VALUES(102, NULL); -- 允许未分配班级
- 插入无效外键值报错:
三、综合案例解析
场景:设计商店数据库(商品、客户、购买表)
-- 商品表
CREATE TABLE goods (goods_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '商品编号',goods_name VARCHAR(32) NOT NULL COMMENT '商品名称',unitprice INT NOT NULL DEFAULT 0 COMMENT '单价(分)',category VARCHAR(12) COMMENT '分类',provider VARCHAR(64) NOT NULL COMMENT '供应商'
);-- 客户表
CREATE TABLE customer (customer_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '客户编号',name VARCHAR(32) NOT NULL COMMENT '姓名',email VARCHAR(64) UNIQUE KEY COMMENT '邮箱',sex ENUM('男','女') NOT NULL COMMENT '性别',card_id CHAR(18) UNIQUE KEY COMMENT '身份证'
);-- 购买表(外键关联)
CREATE TABLE purchase (order_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '订单号',customer_id INT COMMENT '客户编号',goods_id INT COMMENT '商品编号',nums INT DEFAULT 0 COMMENT '购买数量',FOREIGN KEY (customer_id) REFERENCES customer(customer_id),FOREIGN KEY (goods_id) REFERENCES goods(goods_id)
);
四、关键注意事项
- 主键与业务无关:推荐使用自增ID,避免业务调整影响主键。
- 外键性能:外键约束可能影响插入/更新性能,高频写入场景需谨慎使用。
- 唯一键与NULL:唯一键允许NULL,但多个NULL不视为重复。
- 自增长字段:仅支持整数类型,且一张表只能有一个自增长字段。
MySQL基本查询操作
1. Create(增)
- 语法:
INSERT INTO 表名 [(列名,...)] VALUES (值列表)[, (值列表)...];
- 操作细节:
- 全列插入:值与表结构列顺序一致,可省略列名。
INSERT INTO students VALUES (100, 10000, '唐三藏', NULL);
- 指定列插入:插入部分列,未指定列使用默认值或NULL。
INSERT INTO students (id, sn, name) VALUES (102, 20001, '曹孟德');
- 冲突处理:
- 更新重复键:
ON DUPLICATE KEY UPDATE
INSERT INTO students (id, sn, name) VALUES (100, 10010, '唐大师') ON DUPLICATE KEY UPDATE sn = 10010, name = '唐大师';
- 替换重复键:
REPLACE
(删除旧记录后插入新记录)。REPLACE INTO students (sn, name) VALUES (20001, '曹阿晴');
- 更新重复键:
- 全列插入:值与表结构列顺序一致,可省略列名。
2. Retrieve(查)
- 语法:
SELECT [DISTINCT] 列名 FROM 表名 [WHERE ...] [ORDER BY ...] [LIMIT ...];
- 操作细节:
-
基础查询:
- 全列查询(不推荐):
SELECT * FROM exam_result;
- 指定列查询:
SELECT id, name FROM exam_result;
- 表达式查询:
SELECT name, math + 10 AS math_plus FROM exam_result;
- 别名:
SELECT name, chinese + math + english 总分 FROM exam_result;
- 去重:
SELECT DISTINCT math FROM exam_result;
- 全列查询(不推荐):
-
条件过滤(WHERE):
- 比较运算符:
>
,=
,<=>
,BETWEEN
,IN
,LIKE
(%
匹配任意字符,_
匹配单个字符)。 - 逻辑运算符:
AND
,OR
,NOT
。 - 案例:
-- 英语不及格 SELECT name, english FROM exam_result WHERE english < 60; -- 姓孙的同学 SELECT name FROM exam_result WHERE name LIKE '孙%'; -- 总分 < 200(WHERE中不能使用别名) SELECT name, chinese + math + english 总分 FROM exam_result WHERE chinese + math + english < 200;
- 比较运算符:
-
排序(ORDER BY):
- 默认升序(ASC),降序用DESC。
- 多字段排序:按书写顺序优先级。
SELECT name, math, english FROM exam_result ORDER BY math DESC, english;
-
分页(LIMIT):
- 语法:
LIMIT n OFFSET s
(从s开始取n条,s起始为0)。-- 第2页(每页3条) SELECT * FROM exam_result ORDER BY id LIMIT 3 OFFSET 3;
- 语法:
-
3. Update(改)
- 语法:
UPDATE 表名 SET 列名=值 [WHERE ...] [ORDER BY ...] [LIMIT ...];
- 操作细节:
- 单列更新:
UPDATE exam_result SET math = 80 WHERE name = '孙悟空';
- 多列更新:
UPDATE exam_result SET math = 60, chinese = 70 WHERE name = '曹孟德';
- 表达式更新:
-- 总分倒数前三的数学加30分 UPDATE exam_result SET math = math + 30 ORDER BY chinese + math + english LIMIT 3;
- 慎用全表更新:无WHERE条件时更新全表。
- 单列更新:
4. Delete(删)
- 语法:
DELETE FROM 表名 [WHERE ...] [ORDER BY ...] [LIMIT ...];
- 操作细节:
- 删除指定数据:
DELETE FROM exam_result WHERE name = '孙悟空';
- 清空表:
DELETE FROM 表名
:逐行删除,自增值保留。TRUNCATE 表名
:快速清空,重置自增值,不可回滚。
- 删除指定数据:
5. 高级操作
-
聚合函数:
COUNT
,SUM
,AVG
,MAX
,MIN
,支持DISTINCT
。-- 统计数学成绩种类数 SELECT COUNT(DISTINCT math) FROM exam_result; -- 计算平均总分 SELECT AVG(chinese + math + english) 平均总分 FROM exam_result;
-
GROUP BY 分组:
- 按部门统计平均工资:
SELECT deptno, AVG(sal) FROM EMP GROUP BY deptno;
HAVING
过滤分组:SELECT deptno, AVG(sal) FROM EMP GROUP BY deptno HAVING AVG(sal) < 2000;
- 按部门统计平均工资:
6. 注意事项
- 执行顺序:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
。 - NULL处理:
= NULL
不安全,需用IS NULL
或<=>
。- 聚合函数忽略NULL(如
COUNT(qq)
仅统计非NULL值)。
- 性能提示:
- 避免全列查询(
SELECT *
)。 - 分页时建议用
LIMIT
防止全表扫描。
- 避免全列查询(
7. 实战技巧
- 去重插入:通过临时表实现原子操作。
CREATE TABLE no_duplicate_table LIKE duplicate_table; INSERT INTO no_duplicate_table SELECT DISTINCT * FROM duplicate_table; RENAME TABLE duplicate_table TO old_table, no_duplicate_table TO duplicate_table;
- 分页优化:按主键分页,避免
OFFSET
过大时性能问题。