MySQL(三)

十一. 数据处理之增删改

INSERT INTO 表名 VALUES (value1,value2,…);

#0. 储备工作
USE atguigudb;

CREATE TABLE IF NOT EXISTS emp1(
id INT,
`name` VARCHAR(15),
hire_date DATE,
salary DOUBLE(10,2)
);

#方式1:一条一条的添加数据

# ① 没有指明添加的字段
#正确的 
INSERT INTO emp1
VALUES (1,'Tom','2000-12-21',3400); #注意:一定要按照声明的字段的先后顺序添加
#错误的
INSERT INTO emp1
VALUES (2,3400,'2000-12-21','Jerry');

# ② 指明要添加的字段 (推荐)
INSERT INTO emp1(id,hire_date,salary,`name`)
VALUES(2,'1999-09-09',4000,'Jerry');
# 说明:没有进行赋值的hire_date 的值为 null
INSERT INTO emp1(id,salary,`name`)
VALUES(3,4500,'shk');

# ③ 同时插入多条记录 (推荐)
INSERT INTO emp1(id,NAME,salary)
VALUES
(4,'Jim',5000),
(5,'张俊杰',5500);

因为MySQL执行单条INSERT语句插入多行数据比使用多条INSERT语句快,所以在插入多条记录时最好选择使用单条INSERT语句的方式插入

方式二

#方式2:将查询结果插入到表中

SELECT * FROM emp1;

INSERT INTO emp1(id,NAME,salary,hire_date)
SELECT employee_id,last_name,salary,hire_date  # 查询的字段一定要与添加到的表的字段一一对应
FROM employees
WHERE department_id IN (70,60);

将查询语句的结果集插入另一张表,要考虑字段的数据类型是否匹配。比如说varchar类型,查询的表长度是25,待插入的表是15,如果查询的表这个字段实际的数据没有超过15的,则插入成功,否则报错

还比如double,查询的表是(8,2),带插入的表是(10,2),首先精度是一样的,但是范围不一样。最终要看实际的数据是否在两者的交集

说明:emp1表中要添加数据的字段的长度不能低于employees表中查询的字段的长度。

查询语句的结果可以做什么
(1)基于查询结果创建一张表

CREATE TABLE myemp2
AS
SELECT employee_id,last_name,salary
FROM employees;

(2)将查询结果插入一张表

改UPDATE … SET … WHERE …

# UPDATE .... SET .... WHERE ...
# 可以实现批量修改数据的。
UPDATE emp1
SET hire_date = CURDATE()
WHERE id = 5;

更新表emp1,将hire_date字段的值改成当前时间,过滤hire_date字段的数据,因为并不是每一条记录都要改,我们只改id=5的这一行记录的hire_date

#同时修改一条数据的多个字段
UPDATE emp1
SET hire_date = CURDATE(),salary = 6000
WHERE id = 4;
#题目:将表中姓名中包含字符a的提薪20%
UPDATE emp1
SET salary = salary * 1.2
WHERE NAME LIKE '%a%';

下例约束造成修改不成功

#修改数据时,是可能存在不成功的情况的。(可能是由于约束的影响造成的)
UPDATE employees
SET department_id = 10000
WHERE employee_id = 102;

删DELETE FROM … WHERE…

DELETE FROM … WHERE…

数据都是一条记录一条记录的删除的


DELETE FROM emp1
WHERE id = 1;

#在删除数据时,也有可能因为约束的影响,导致删除失败
DELETE FROM departments
WHERE department_id = 50;

小结:DML操作默认情况下,执行完以后都会自动提交数据。
如果希望执行完以后不自动提交数据,则需要使用 SET autocommit = FALSE.

mysql8新特性-计算列

简单来说就是某一列的值是通过别的列计算得来的。例如,a列值为1、b列值为2,c列不需要手动插入,定义a+b的结果为c的值,那么c就是计算列,是通过别的列计算得来的

USE atguigudb;

CREATE TABLE test1(
a INT,
b INT,
c INT GENERATED ALWAYS AS (a + b) VIRTUAL  #字段c即为计算列
);
INSERT INTO test1(a,b)
VALUES(10,20);

其结果是:
在这里插入图片描述
更改字段a的值

UPDATE test1
SET a = 100;

结果为:
在这里插入图片描述
计算列同步发生了变化

DDL和DML综合案例

# 1、创建数据库test01_library
CREATE DATABASE IF NOT EXISTS test01_library CHARACTER SET 'utf8';

USE test01_library;

# 2、创建表 books,表结构如下:
CREATE TABLE IF NOT EXISTS books(
id INT,
`name` VARCHAR(50),
`authors` VARCHAR(100),
price FLOAT,
pubdate YEAR,
note VARCHAR(100),
num INT
);

DESC books;

SELECT * FROM books;
# 3、向books表中插入记录

# 1)不指定字段名称,插入第一条记录
INSERT INTO books
VALUES(1,'Tal of AAA','Dickes',23,'1995','novel',11);
# 2)指定所有字段名称,插入第二记录
INSERT INTO books(id,NAME,AUTHORS,price,pubdate,note,num)
VALUES(2,'EmmaT','Jane lura',35,'1993','joke',22);
# 3)同时插入多条记录(剩下的所有记录)
INSERT INTO books(id,NAME,AUTHORS,price,pubdate,note,num)
VALUES
(3,'Story of Jane','Jane Tim',40,2001,'novel',0),
(4,'Lovey Day','George Byron',20,2005,'novel',30),
(5,'Old land','Honore Blade',30,2010,'Law',0),
(6,'The Battle','Upton Sara',30,1999,'medicine',40),
(7,'Rose Hood','Richard haggard',28,2008,'cartoon',28);


# 4、将小说类型(novel)的书的价格都增加5。
UPDATE books
SET price = price + 5
WHERE note = 'novel';

# 5、将名称为EmmaT的书的价格改为40,并将说明改为drama。
UPDATE books
SET price = 40,note = 'drama'
WHERE NAME = 'EmmaT';

# 6、删除库存为0的记录。
DELETE FROM books
WHERE num = 0;

# 7、统计书名中包含a字母的书
SELECT NAME
FROM books
WHERE NAME LIKE '%a%';

# 8、统计书名中包含a字母的书的数量和库存总量
SELECT COUNT(*),SUM(num)
FROM books
WHERE NAME LIKE '%a%';

# 9、找出“novel”类型的书,按照价格降序排列

SELECT NAME,note,price
FROM books
WHERE note = 'novel'
ORDER BY price DESC;

# 10、查询图书信息,按照库存量降序排列,如果库存量相同的按照note升序排列
SELECT *
FROM books
ORDER BY num DESC,note ASC;


# 11、按照note分类统计书的数量
SELECT note,COUNT(*)
FROM books
GROUP BY note;

# 12、按照note分类统计书的库存量,显示库存量超过30本的
SELECT note,SUM(num)
FROM books
GROUP BY note
HAVING SUM(num) > 30;

# 13、查询所有图书,每页显示5本,显示第二页
SELECT *
FROM books
LIMIT 5,5;

# 14、按照note分类统计书的库存量,显示库存量最多的
SELECT note,SUM(num) sum_num
FROM books
GROUP BY note
ORDER BY sum_num DESC
LIMIT 0,1;

# 15、查询书名达到10个字符的书,不包括里面的空格
SELECT CHAR_LENGTH(REPLACE(NAME,' ',''))
FROM books;

SELECT NAME
FROM books
WHERE CHAR_LENGTH(REPLACE(NAME,' ','')) >= 10;

# 16、查询书名和类型,其中note值为novel显示小说,law显示法律,medicine显示医药,
#cartoon显示卡通,joke显示笑话
SELECT NAME "书名",note,CASE note WHEN 'novel' THEN '小说'
				  WHEN 'law' THEN '法律'
				  WHEN 'medicine' THEN '医药'
				  WHEN 'cartoon' THEN '卡通'
				  WHEN 'joke' THEN '笑话'
				  ELSE '其他'
				  END "类型"
FROM books;


# 17、查询书名、库存,其中num值超过30本的,显示滞销,大于0并低于10的,
#显示畅销,为0的显示需要无货
SELECT NAME AS "书名",num AS "库存", CASE WHEN num > 30 THEN '滞销'
					  WHEN num > 0 AND num < 10 THEN '畅销'
					  WHEN num = 0 THEN '无货'
					  ELSE '正常'
					  END "显示状态"
FROM books;

# 18、统计每一种note的库存量,并合计总量
SELECT IFNULL(note,'合计库存总量') AS note,SUM(num)
FROM books
GROUP BY note WITH ROLLUP;

# 19、统计每一种note的数量,并合计总量
SELECT IFNULL(note,'合计总量') AS note,COUNT(*)
FROM books
GROUP BY note WITH ROLLUP;

# 20、统计库存量前三名的图书
SELECT *
FROM books
ORDER BY num DESC
LIMIT 0,3;

# 21、找出最早出版的一本书
SELECT *
FROM books
ORDER BY pubdate ASC
LIMIT 0,1;

# 22、找出novel中价格最高的一本书
SELECT *
FROM books
WHERE note = 'novel'
ORDER BY price DESC
LIMIT 0,1;

# 23、找出书名中字数最多的一本书,不含空格

SELECT *
FROM books
ORDER BY CHAR_LENGTH(REPLACE(NAME,' ','')) DESC
LIMIT 0,1;

十二. mysql数据类型(性能调优)

在这里插入图片描述
decimal:精度更高

常见数据类型的属性(约束???)
在这里插入图片描述

#1.关于属性:character set name

SHOW VARIABLES LIKE 'character_%';

在这里插入图片描述

#创建数据库时指名字符集
CREATE DATABASE IF NOT EXISTS dbtest12 CHARACTER SET 'utf8';

SHOW CREATE DATABASE dbtest12;

#创建表的时候,指名表的字符集
CREATE TABLE temp(
id INT
) CHARACTER SET 'utf8';

SHOW CREATE TABLE temp;

#创建表,指名表中的字段时,可以指定字段的字符集
CREATE TABLE temp1(
id INT,
NAME VARCHAR(15) CHARACTER SET 'gbk'

);

整数类型

在这里插入图片描述

USE dbtest12;

CREATE TABLE test_int1(
f1 TINYINT,
f2 SMALLINT,
f3 MEDIUMINT,
f4 INTEGER,
f5 BIGINT

);

DESC test_int1;

INSERT INTO test_int1(f1)
VALUES(12),(-12),(-128),(127);

SELECT * FROM test_int1;

#Out of range value for column 'f1' at row 1
INSERT INTO test_int1(f1)
VALUES(128);

对于tinyint类型的数据,上例要添加128,越界了,报错

mysql5.7和mysql8显示表结构

在mysql5.7中,查询表结构时,返回的结果是:
在这里插入图片描述
可以看到在每一个类型的后面都有括号和数字,其意思是十进制的位数。比如说tinyint,占一个字节,范围是-128到127.换算成十进制,下限占4位.

mysql8就不再提供这个数据

整数类型的可选属性

M

M : 表示显示宽度,M的取值范围是(0, 255)。例如,int(5):当数据宽度小于5位的时候在数字前面需要用
字符填满宽度

该项功能需要配合“ ZEROFILL ”使用,表示用“0”填满宽度,否则指定显示宽度无效

CREATE TABLE test_int2(
f1 INT,
f2 INT(5),
f3 INT(5) ZEROFILL  #① 显示宽度为5。当insert的值不足5位时,使用0填充。 ②当使用ZEROFILL时,自动会添加UNSIGNED
)

INSERT INTO test_int2(f1,f2)
VALUES(123,123),(123456,123456);

上例的结果是:
在这里插入图片描述

INSERT INTO test_int2(f3)
VALUES(123),(123456);

上例的结果是:
在这里插入图片描述

unsigned
CREATE TABLE test_int3(
f1 INT UNSIGNED
);

DESC test_int3;

其结果为:
在这里插入图片描述
无符号int类型数据的范围是0到4294967295,换算成十进制所占位数为10位

INSERT INTO test_int3
VALUES(2412321);

#Out of range value for column 'f1' at row 1。报错
INSERT INTO test_int3
VALUES(4294967296);
zerofill

0填充,(如果某列是ZEROFILL,那么MySQL会自动为当前列添加UNSIGNED属性),如果指定了ZEROFILL只是表示不够M位时,用0在左边填充,如果超过M位,只要不超过数据存储范围即可。

适用场景

TINYINT :一般用于枚举数据,比如系统设定取值范围很小且固定的场景。

SMALLINT :可以用于较小范围的统计数据,比如统计工厂的固定资产库存数量等。

MEDIUMINT :用于较大整数的计算,比如车站每日的客流量等。

INT、INTEGER :取值范围足够大,一般情况下不用考虑超限问题,用得最多。比如商品编号。

BIGINT :只有当你处理特别巨大的整数时才会用到。比如双十一的交易量、大型门户网站点击量、证券公司衍生产品持仓等。

浮点类型

在这里插入图片描述
MySQL支持的浮点数类型,分别是 FLOAT、DOUBLE、REAL

REAL默认就是 DOUBLE。如果你把 SQL 模式设定为启用“ REAL_AS_FLOAT ”,那 么,MySQL 就认为REAL 是 FLOAT

为什么浮点数类型的无符号数取值范围,只相当于有符号数取值范围的一半,也就是只相当于有符号数取值范围大于等于零的部分呢??????
A:MySQL 存储浮点数的格式为: 符号(S) 、 尾数(M) 和 阶码(E) 。因此,无论有没有符号,MySQL 的浮点数都会存储表示符号的部分。因此, 所谓的无符号数取值范围,其实就是有符号数取值范围大于等于零的部分
详情见组原的课程

mysql数据库的精度说明

MySQL允许使用 非标准语法 (其他数据库未必支持,因此如果涉及到数据迁移,则最好不要这么用): FLOAT(M,D) 或 DOUBLE(M,D) 。这里,M称为 精度 ,D称为 标度 。(M,D)中 M=整数位+小数位,D=小数位。 D<=M<=255,0<=D<=30。这里说的位数应该是十进制的位数

对于double类型,小数最多30位,整数位最多225位

定义为FLOAT(5,2)的一个列可以显示为-999.99-999.99。如果超过这个范围会报错。整数位3位,小数位2位,不包括符号位

CREATE TABLE test_double1(
f1 FLOAT,
f2 FLOAT(5,2),
f3 DOUBLE,
f4 DOUBLE(5,2)
);

DESC test_double1;

上例的结果是:
在这里插入图片描述

INSERT INTO test_double1(f3,f4)
VALUES(123.45,123.456); #存在四舍五入

上例增加的数据小数位超过了创建时设定的精度,自动四舍五入

#Out of range value for column 'f4' at row 1
INSERT INTO test_double1(f3,f4)
VALUES(123.45,1234.456);

#Out of range value for column 'f4' at row 1
INSERT INTO test_double1(f3,f4)
VALUES(123.45,999.995);

整数位超过了设定得精度,不像小数位,报错

浮点数的精度损失

CREATE TABLE test_double2(
f1 DOUBLE
);

INSERT INTO test_double2
VALUES(0.47),(0.44),(0.19);

SELECT SUM(f1)
FROM test_double2;

其结果为:
在这里插入图片描述

SELECT SUM(f1) = 1.1,1.1 = 1.1
FROM test_double2;

其结果表示SUM(f1)的结果不等于1.1

把数据类型改成 FLOAT,然后运行求和查询,得到的是, 1.0999999940395355。显然,误差更大了

定点数类型decimal

在这里插入图片描述
使用 DECIMAL(M,D) 的方式表示高精度小数。其中,M被称为精度,D被称为标度。0<=M<=65,0<=D<=30,D<M。

精度更高,但是表示的范围变窄了

例如,定义DECIMAL(5,2)的类型,表示该列取值范围是-999.99~999.99

定点数在MySQL内部是以 字符串 的形式进行存储,这就决定了它一定是精准的

当DECIMAL类型不指定精度和标度时,其默认为DECIMAL(10,0)。当数据的精度超出了定点数类型的
精度范围时,则MySQL同样会进行四舍五入处理

CREATE TABLE test_decimal1(
f1 DECIMAL,
f2 DECIMAL(5,2)
);

DESC test_decimal1;

INSERT INTO test_decimal1(f1)
VALUES(123),(123.45); # 123.45四舍五入

SELECT * FROM test_decimal1;

INSERT INTO test_decimal1(f2)
VALUES(999.99);

INSERT INTO test_decimal1(f2)
VALUES(67.567);#存在四舍五入

#Out of range value for column 'f2' at row 1
INSERT INTO test_decimal1(f2)
VALUES(1267.567);# 报错

#Out of range value for column 'f2' at row 1
INSERT INTO test_decimal1(f2)
VALUES(999.995);# 最终整数位越界,报错

定点数和浮点数的替换

ALTER TABLE test_double2
MODIFY f1 DECIMAL(5,2);

DESC test_double2;

SELECT SUM(f1)
FROM test_double2;

SELECT SUM(f1) = 1.1,1.1 = 1.1
FROM test_double2;

使用场景

(1)浮点数相对于定点数的优点是在长度一定的情况下,浮点类型取值范围大,但是不精准,适用于需要取值范围大,又可以容忍微小误差的科学计算场景(比如计算化学、分子建模、流体动力学等)

(2)定点数类型取值范围相对小,但是精准,没有误差,适合于对精度要求极高的场景 (比如涉及金额计算的场景)

位类型

在这里插入图片描述
注意,这个长度指的是二进制的长度

BIT类型,如果没有指定(M),默认是1位。这个1位,表示只能存1位的二进制值。这里(M)是表示二进制的位数,位数最小值为1,最大值为64

CREATE TABLE test_bit1(
f1 BIT,
f2 BIT(5),
f3 BIT(64)
);

DESC test_bit1;

INSERT INTO test_bit1(f1)
VALUES(0),(1);

SELECT *
FROM test_bit1;

#Data too long for column 'f1' at row 1
INSERT INTO test_bit1(f1)
VALUES(2);

INSERT INTO test_bit1(f2)
VALUES(31);

#Data too long for column 'f2' at row 1
INSERT INTO test_bit1(f2)
VALUES(32);

可以在select语句中使用函数bin()输出二进制形式,hex()输出十六进制形式

SELECT BIN(f1),BIN(f2),HEX(f1),HEX(f2)
FROM test_bit1;

在这里插入图片描述
二进制11111 = 十进制31 = 十六进制1F(15 + 16)

#此时+0以后,可以以十进制的方式显示数据
SELECT f1 + 0, f2 + 0
FROM test_bit1;

+0之前

SELECT f1,f2
FROM test_bit1;

其结果为
在这里插入图片描述
+0之后的结果为:
在这里插入图片描述

日期与时间类型

日期与时间是重要的信息,原因是客户需要知道数据的
时间标签

MySQL8.0版本支持的日期和时间类型主要有:YEAR类型、TIME类型、DATE类型、DATETIME类型和TIMESTAMP类型:
**加粗样式**
为什么时间类型 TIME 的取值范围不是 -23:59:59~23:59:59 呢?原因是 MySQL 设计的 TIME 类型,不光表
示一天之内的时间,而且可以用来表示一个时间间隔,这个时间间隔可以超过 24 小时

timestamp:时间戳
stamp:戳,印迹

year类型

以4位字符串或数字格式表示YEAR类型,其格式为YYYY,最小值为1901,最大值为2155

从MySQL5.5.27开始,2位格式的YEAR已经不推荐使用。YEAR默认格式就是“YYYY”

CREATE TABLE test_year(
f1 YEAR,
f2 YEAR(4)
);

DESC test_year;

INSERT INTO test_year(f1)
VALUES('2021'),(2022);

SELECT * FROM test_year;

INSERT INTO test_year(f1)
VALUES ('2155');

#Out of range value for column 'f1' at row 1
INSERT INTO test_year(f1)
VALUES ('2156');# 越界

INSERT INTO test_year(f1)
VALUES ('69'),('70');

INSERT INTO test_year(f1)
VALUES (0),('00');

date类型

格式为 YYYY-MM-DD

YYYYMMDD格式会被转化为YYYY-MM-DD格式

CREATE TABLE test_date1(
f1 DATE
);

DESC test_date1;

INSERT INTO test_date1
VALUES ('2020-10-01'), ('20201001'),(20201001);

INSERT INTO test_date1
VALUES ('00-01-01'), ('000101'), ('69-10-01'), ('691001'), ('70-01-01'), ('700101'), ('99-01-01'), ('990101');

INSERT INTO test_date1
VALUES (000301), (690301), (700301), (990301); #存在隐式转换

INSERT INTO test_date1
VALUES (CURDATE()),(CURRENT_DATE()),(NOW());

SELECT *
FROM test_date1;

time类型

使用“HH:MM:SS”格式来表示

’ D HH:MM:SS’ 、’ HH:MM:SS ‘、’ HH:MM ‘、’ D HH:MM ‘、’ D HH ‘或’ SS ’

其中D表示天,其最小值为0,最大值为34
D会被转化为小时,计算格式为D*24+HH

CREATE TABLE test_time1(
f1 TIME
);

DESC test_time1;

INSERT INTO test_time1
VALUES('2 12:30:29'), ('12:35:29'), ('12:40'), ('2 12:40'),('1 05'), ('45');

在这里插入图片描述

INSERT INTO test_time1
VALUES ('123520'), (124011),(1210);

INSERT INTO test_time1
VALUES (NOW()), (CURRENT_TIME()),(CURTIME());

SELECT *
FROM test_time1;

datetime类型

表示为 YYYY-MM-DD HH:MM:SS

最小值为1000-01-01 00:00:00,最大值为9999-12-03 23:59:59

CREATE TABLE test_datetime1(
dt DATETIME
);

INSERT INTO test_datetime1
VALUES ('2021-01-01 06:50:30'), ('20210101065030');

INSERT INTO test_datetime1
VALUES ('99-01-01 00:00:00'), ('990101000000'), ('20-01-01 00:00:00'), ('200101000000');

INSERT INTO test_datetime1
VALUES (20200101000000), (200101000000), (19990101000000), (990101000000);
 
INSERT INTO test_datetime1
VALUES (CURRENT_TIMESTAMP()), (NOW()),(SYSDATE());

SELECT *
FROM test_datetime1;

timestamp类型

显示格式与DATETIME类型相同,都是 YYYY-MM-DD
HH:MM:SS

存储的时间范围比DATETIME要小很多,只能存储
“1970-01-01 00:00:01 UTC”到“2038-01-19 03:14:07 UTC”之间的时间。其中,UTC表示世界统一时间,也叫
作世界标准时间

CREATE TABLE test_timestamp1(
ts TIMESTAMP
);

INSERT INTO test_timestamp1
VALUES ('1999-01-01 03:04:50'), ('19990101030405'), ('99-01-01 03:04:05'), ('990101030405');

INSERT INTO test_timestamp1
VALUES ('2020@01@01@00@00@00'), ('20@01@01@00@00@00');

INSERT INTO test_timestamp1
VALUES (CURRENT_TIMESTAMP()), (NOW());

#Incorrect datetime value
INSERT INTO test_timestamp1
VALUES ('2038-01-20 03:14:07');

SELECT *
FROM test_timestamp1;

datetime和timestamp的区别

时区:timestamp类型底层存的是毫秒数,这个数值的计算需要时区的参与。编码与解码要同一个时区的参与,如果时区不同,算出来的日期也就不正确了

存储数据的时候需要对当前时间所在的时区进行转换,查询数据的时候再将时间转换回当前的时区。因此,使用TIMESTAMP存储的同一个时间值,在不同的时区查询时会显示不同的时间

CREATE TABLE temp_time(
d1 DATETIME,
d2 TIMESTAMP
);

INSERT INTO temp_time VALUES('2021-9-2 14:45:52','2021-9-2 14:45:52');

INSERT INTO temp_time VALUES(NOW(),NOW());

SELECT * FROM temp_time;

#修改当前的时区
SET time_zone = '+9:00';

SELECT * FROM temp_time;

(1)TIMESTAMP存储空间比较小,表示的日期时间范围也比较小
(2)底层存储方式不同,TIMESTAMP底层存储的是毫秒值,距离1970-1-1 0:0:0 0毫秒的毫秒值。
两个日期比较大小或日期计算时,TIMESTAMP更方便、更快。
(3)TIMESTAMP和时区有关。TIMESTAMP会根据用户的时区不同,显示不同的结果。而DATETIME则只能
反映出插入时当地的时区,其他时区的人查看数据必然会有误差的

开发经验

用得最多的日期时间类型,就是 DATETIME
这个数据类型包括了完整的日期和时间信息,取值范围也最大,使用起来比较方便

一般存注册时间、商品发布时间等,不建议使用DATETIME存储,而是使用 时间戳 ,因为
DATETIME虽然直观,但不便于计算

文本字符串类型

二进制类型

json类型

十三. 约束constrain

数据完整性(Data Integrity)是指数据的精确性(Accuracy)和可靠性(Reliability)

约束:针对对表数据进行额外的条件限制

(1)实体完整性(Entity Integrity) :例如,同一个表中,不能存在两条完全相同无法区分的记录

(2)域完整性(Domain Integrity) :例如:年龄范围0-120,性别范围“男/女”

(3)引用完整性(Referential Integrity) :例如:员工所在部门,在部门表中要能找到这个部门(关联查询)

(4)用户自定义完整性(User-defined Integrity) :例如:用户名唯一、密码不能为空等,本部门经理的工资不得高于本部门职工的平均工资的5倍

添加或者删除约束

CREATE TABLE时添加约束

ALTER TABLE 时增加约束、删除约束

如何查看约束

SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'test1';

information_schema:mysql自带的数据库
table_constraints:information_schema数据库下的表

分类

角度1:约束的字段的个数
单列约束 vs 多列约束

角度2:约束的作用范围

列级约束:将此约束声明在对应字段的后面,只能作用在一个列上

表级约束:在表中所有字段都声明完,在所有字段的后面声明的约束。可以作用在多个列上

角度3:约束的作用(或功能)

① not null (非空约束)
② unique (唯一性约束)
③ primary key (主键约束)
④ foreign key (外键约束)
⑤ check (检查约束)
⑥ default (默认值约束)

非空约束 not null

这个字段的数据不能为null

所有的类型的值都可以是NULL,包括INT、FLOAT等数据类型

非空约束只能出现在表对象的列上,只能某个列单独限定非空,不能组合非空.
所谓组合非空,也就是表级约束,对表的所有字段的数据进行约束
非空约束不能进行表级约束

mysql关键字太多了,时间一长很容易忘:

alter:用于表的管理
(1)添加字段

ALTER TABLE 表名 
ADDCOLUMN】 字段名 字段类型 【FIRST|AFTER 字段名】;

ALTER TABLE myemp1
ADD email VARCHAR(45) AFTER emp_name;

(2)修改一个字段:数据类型、长度、默认值、位置

ALTER TABLE 表名 
MODIFYCOLUMN】 字段名1 字段类型 【DEFAULT 默认值】【FIRST|AFTER 字段名2;

ALTER TABLE myemp1
MODIFY emp_name VARCHAR(35) DEFAULT 'aaa';

update:用于表数据的更改
update…set…where

在CREATE TABLE时添加约束
#3.1 在CREATE TABLE时添加约束

CREATE TABLE test1(
id INT NOT NULL,
last_name VARCHAR(15) NOT NULL,
email VARCHAR(25),
salary DECIMAL(10,2)

);

DESC test1;

INSERT INTO test1(id,last_name,email,salary)
VALUES(1,'Tom','tom@126.com',3400);

#错误:Column 'last_name' cannot be null
INSERT INTO test1(id,last_name,email,salary)
VALUES(2,NULL,'tom1@126.com',3400);

#错误:Column 'id' cannot be null
INSERT INTO test1(id,last_name,email,salary)
VALUES(NULL,'Jerry','jerry@126.com',3400);

INSERT INTO test1(id,email)
VALUES(2,'abc@126.com');

UPDATE test1
SET last_name = NULL
WHERE id = 1;

UPDATE test1
SET email = 'tom@126.com'
WHERE id = 1;
在ALTER TABLE时添加约束
#3.2 在ALTER TABLE时添加约束
SELECT * FROM test1;

DESC test1;

ALTER TABLE test1
MODIFY email VARCHAR(25) NOT NULL;
在ALTER TABLE时删除约束
#3.3 在ALTER TABLE时删除约束
ALTER TABLE test1
MODIFY email VARCHAR(25) NULL;

唯一性约束 unique

字段不能出现重复数据
unique关键字或者是unique key关键字都是可以的

唯一性索引

在CREATE TABLE时添加约束
#4.1 在CREATE TABLE时添加约束
CREATE TABLE test2(
id INT UNIQUE, #列级约束
last_name VARCHAR(15) ,
email VARCHAR(25),
salary DECIMAL(10,2),
#表级约束
CONSTRAINT uk_test2_email UNIQUE(email)
);

uk_test2_email:我们为表级约束起的名。uk表示unique,test2表示作用的表,email表示表中的字段

CONSTRAINT uk_test2_email的作用就是给表级约束起名,可以删掉

真正的表级约束是UNIQUE(email)

注意,表级约束不是指对表的所有字段施加的约束,而是指当所有字段声明完之后才声明的约束,这种约束可以作用于多个列

表级约束的添加就像添加一个字段

DESC test2;


SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'test2';

#在创建唯一约束的时候,如果不给唯一约束命名,就默认和列名相同。

约束为什么还需要起名???
A:删除的时候需要定位是哪一个约束

INSERT INTO test2(id,last_name,email,salary)
VALUES(1,'Tom','tom@126.com',4500);

#错误:Duplicate entry '1' for key 'test2.id'
INSERT INTO test2(id,last_name,email,salary)
VALUES(1,'Tom1','tom1@126.com',4600);

#错误:Duplicate entry 'tom@126.com' for key 'test2.uk_test2_email'
INSERT INTO test2(id,last_name,email,salary)
VALUES(2,'Tom1','tom@126.com',4600);

#可以向声明为unique的字段上添加null值。而且可以多次添加null
INSERT INTO test2(id,last_name,email,salary)
VALUES(2,'Tom1',NULL,4600);

INSERT INTO test2(id,last_name,email,salary)
VALUES(3,'Tom2',NULL,4600);

SELECT * FROM test2;
在ALTER TABLE时添加约束
#4.2 在ALTER TABLE时添加约束

DESC test2;

UPDATE test2
SET salary = 5000
WHERE id = 3;
#方式1:添加表级约束
ALTER TABLE test2
ADD CONSTRAINT uk_test2_sal UNIQUE(salary);
#方式2:添加列级约束
ALTER TABLE test2
MODIFY last_name VARCHAR(15) UNIQUE;
复合的唯一性约束
#4.3 复合的唯一性约束
CREATE TABLE USER(
id INT,
`name` VARCHAR(15),
`password` VARCHAR(25),

#表级约束
CONSTRAINT uk_user_name_pwd UNIQUE(`name`,`password`)
);

INSERT INTO USER
VALUES(1,'Tom','abc');
#可以成功的:
INSERT INTO USER
VALUES(1,'Tom1','abc');

SELECT *
FROM USER;

从上面的例子可以看出,复合的唯一性约束并非是给选中的每一个字段加了唯一性约束,而是将选中字段数据的拼接结果加了唯一性约束。
可以这样说,唯一性约束的查重做法是将选中字段的数据作为哈希表的key;复合唯一性约束则是将多个选中字段的数据的拼接结果作为哈希表的key

实际场景:

#学生表
CREATE TABLE student(
    sid INT,	#学号
    sname VARCHAR(20),	#姓名
    tel CHAR(11) UNIQUE KEY,  #电话
    cardid CHAR(18) UNIQUE KEY #身份证号
);

#课程表
CREATE TABLE course(
    cid INT,  #课程编号
    cname VARCHAR(20)     #课程名称
);

#选课表
CREATE TABLE student_course(
    id INT,
    sid INT,  #学号
    cid INT,  #课程编号
    score INT,
    UNIQUE KEY(sid,cid)  #复合唯一
);
INSERT INTO student VALUES(1,'张三','13710011002','101223199012015623');#成功
INSERT INTO student VALUES(2,'李四','13710011003','101223199012015624');#成功
INSERT INTO course VALUES(1001,'Java'),(1002,'MySQL');#成功

SELECT * FROM student;

SELECT * FROM course;

INSERT INTO student_course VALUES
(1, 1, 1001, 89),
(2, 1, 1002, 90),
(3, 2, 1001, 88),
(4, 2, 1002, 56);#成功

SELECT * FROM student_course;

#错误:Duplicate entry '2-1002' for key 'student_course.sid'
INSERT INTO student_course VALUES
(5,2,1002,67);
删除唯一性约束

这一块涉及到索引,在mysql的可视化软件sqlyog里可以看到每张表的索引
在这里插入图片描述

SELECT * FROM information_schema.table_constraints 
WHERE table_name = 表名;

通过查询information_schema数据库里面的table_constraints表也可以看到选中的表里的约束

#4.4 删除唯一性约束
-- 添加唯一性约束的列上也会自动创建唯一索引。
-- 删除唯一约束只能通过删除唯一索引的方式删除。
-- 删除时需要指定唯一索引名,唯一索引名就和唯一约束名一样。
-- 如果创建唯一约束时未指定名称,如果是单列,就默认和列名相同;如果是组合列,那么默认和()中排在第一个的列名相同。也可以自定义唯一性约束名。

ALTER TABLE test2
DROP INDEX last_name;

ALTER TABLE test2
DROP INDEX uk_test2_sal;

drop index:删掉索引

drop可用于数据库,数据表的管理
删除数据库:drop database
删除数据表:drop table
删除字段:drop column

主键约束 primary key

用来唯一标识表中的一行记录

讲完整性的时候,提到过实体完整性,要求同一个表中,不能存在两条完全相同无法区分的记录。(肯定不是对表中的所有字段做复合的唯一性约束)

主键约束相当于唯一约束+非空约束的组合,主键约束列不允许重复,也不允许出现空值

一个表最多只能有一个主键约束,建立主键约束可以在列级别创建,也可以在表级别上创建

主键索引,和唯一性索引

能够根据主键查询的,就根据主键查询,效率更高。底层是B+树

在CREATE TABLE时添加约束

从对id添加主键约束这一点就可以看出,主键约束为什么是施加在列上。我看着这句话,用来唯一标识表中的一行记录,以为主键约束是约束整张表的

#5.1 在CREATE TABLE时添加约束

#一个表中最多只能有一个主键约束。

#错误:Multiple primary key defined
CREATE TABLE test3(
id INT PRIMARY KEY, #列级约束
last_name VARCHAR(15) PRIMARY KEY,
salary DECIMAL(10,2),
email VARCHAR(25)
);

# 主键约束特征:非空且唯一,用于唯一的标识表中的一条记录。
# 光做唯一性约束,无法避免null的问题
CREATE TABLE test4(
id INT PRIMARY KEY, #列级约束
last_name VARCHAR(15),
salary DECIMAL(10,2),
email VARCHAR(25)
);

#MySQL的主键名总是PRIMARY,就算自己命名了主键约束名也没用。
CREATE TABLE test5(
id INT , 
last_name VARCHAR(15),
salary DECIMAL(10,2),
email VARCHAR(25),
#表级约束
CONSTRAINT pk_test5_id PRIMARY KEY(id)  #没有必要起名字。
);

SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'test5';

INSERT INTO test4(id,last_name,salary,email)
VALUES(1,'Tom',4500,'tom@126.com');

#错误:Duplicate entry '1' for key 'test4.PRIMARY'
# 重复条目 1
INSERT INTO test4(id,last_name,salary,email)
VALUES(1,'Tom',4500,'tom@126.com');

#错误:Column 'id' cannot be null
INSERT INTO test4(id,last_name,salary,email)
VALUES(NULL,'Tom',4500,'tom@126.com');

SELECT * FROM test4;

# 复合情况
CREATE TABLE user1(
id INT,
NAME VARCHAR(15),
PASSWORD VARCHAR(25),

PRIMARY KEY (NAME,PASSWORD)

);
#如果是多列组合的复合主键约束,那么这些列都不允许为空值,并且组合的值不允许重复。
INSERT INTO user1
VALUES(1,'Tom','abc');

INSERT INTO user1
VALUES(1,'Tom1','abc');
#错误:Column 'name' cannot be null
INSERT INTO user1
VALUES(1,NULL,'abc');

SELECT * FROM user1;

如果是多列组合的复合主键约束,那么这些列都不允许为空值,并且组合的值不允许重复

在ALTER TABLE时添加约束
#5.2 在ALTER TABLE时添加约束

CREATE TABLE test6(
id INT ,
last_name VARCHAR(15),
salary DECIMAL(10,2),
email VARCHAR(25)
);

DESC test6;

ALTER TABLE test6
ADD PRIMARY KEY (id);
删除主键约束
#5.3 如何删除主键约束 (在实际开发中,不会去删除表中的主键约束!)
ALTER TABLE test6
DROP PRIMARY KEY;

不需要像删除唯一性约束,是要删除唯一性索引

自增列 auto_increment

某个字段的值自增

默认从1开始,比较符合生产需要。比如说员工id,从1开始计数

在CREATE TABLE时添加

自增长列约束的列必须是键列(主键列,唯一键列)
自增约束的列的数据类型必须是整数类型

将主键列设为自增列在实际开发中很有用,比如说id,这样在添加数据的时候就不需要再插入id了,id会自动的加上

# 6.1 在CREATE TABLE时添加
CREATE TABLE test7(
id INT PRIMARY KEY AUTO_INCREMENT,
last_name VARCHAR(15) 
);
#开发中,一旦主键作用的字段上声明有AUTO_INCREMENT,则我们在添加数据时,就不要给主键对应的字段去赋值了。
INSERT INTO test7(last_name)
VALUES('Tom');

SELECT * FROM test7;

#当我们向主键(含AUTO_INCREMENT)的字段上添加0 或 null时,实际上会自动的往上添加指定的字段的数值
INSERT INTO test7(id,last_name)
VALUES(0,'Tom');

INSERT INTO test7(id,last_name)
VALUES(NULL,'Tom');

# 成功了,因为主键列已有的数据没有10,符合主键列对数据的约束
# 非空且唯一
INSERT INTO test7(id,last_name)
VALUES(10,'Tom');

# 成功了,且按序存储记录
INSERT INTO test7(id,last_name)
VALUES(-10,'Tom');
在ALTER TABLE 时添加
#6.2 在ALTER TABLE 时添加
CREATE TABLE test8(
id INT PRIMARY KEY ,
last_name VARCHAR(15) 
);

DESC test8;

ALTER TABLE test8
MODIFY id INT AUTO_INCREMENT;
在ALTER TABLE 时删除
#6.3 在ALTER TABLE 时删除

ALTER TABLE test8
MODIFY id INT ;
自增变量的持久化
#在MySQL 5.7中演示
CREATE TABLE test9(
id INT PRIMARY KEY AUTO_INCREMENT
);

INSERT INTO test9
VALUES(0),(0),(0),(0);

# 上面插入四条数据后,id 分别为1,2,3,4

SELECT * FROM test9;

DELETE FROM test9
WHERE id = 4;

INSERT INTO test9
VALUES(0);
# 删除第四条记录,并插入一条记录后,id为1,2,3,5

DELETE FROM test9
WHERE id = 5;
# 删除id=5的这条数据,id为1,2,3
#重启服务器

SELECT * FROM test9;
# id为1,2,3

INSERT INTO test9
VALUES(0);
# id为1,2,3,4

说明:mysql5.7 auto_increment维护了一个自增变量,重启后,这个自增变量就重置了

#在MySQL 8.0中演示
CREATE TABLE test9(
id INT PRIMARY KEY AUTO_INCREMENT
);

INSERT INTO test9
VALUES(0),(0),(0),(0);

SELECT * FROM test9;

DELETE FROM test9
WHERE id = 4;

INSERT INTO test9
VALUES(0);

DELETE FROM test9
WHERE id = 5;

#重启服务器

SELECT * FROM test9;

INSERT INTO test9
VALUES(0);
# id为1,2,3,6

说明:MySQL 8.0将自增主键的计数器持久化到 重做日志 中。每次计数器发生改变,都会将其写入重做日志中。如果数据库重启,InnoDB会根据重做日志中的信息来初始化计数器的内存值

外键约束 foreign key

限定某个表的某个字段的引用完整性。(查询本表这个字段的这个数据是否在另一张表的同一字段)
比如:员工表的员工所在部门的选择,必须在部门表能找到对应的部分

主从表或父子表

主表(父表):被引用的表,被参考的表
从表(子表):引用别人的表,参考别人的表

例如:员工表的员工所在部门这个字段的值要参考部门表:部门表是主表,员工表是从表

例如:学生表、课程表、选课表:选课表的学生和课程要分别参考学生表和课程表,学生表和课程表是
主表,选课表是从表

在CREATE TABLE 时添加

在从表中声明外键约束,声明对从表中的哪一个字段施加外键约束,以及引用主表中的哪一个字段。

主表被引用的字段必须是主键或唯一约束的列,因为被依赖/被参考的值必须是唯一的

#7.1 在CREATE TABLE 时添加

#主表和从表;父表和子表

#①先创建主表
CREATE TABLE dept1(
dept_id INT,
dept_name VARCHAR(15)
);
#②再创建从表
CREATE TABLE emp1(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(15),
department_id INT,

#表级约束
CONSTRAINT fk_emp1_dept_id FOREIGN KEY (department_id) REFERENCES dept1(dept_id)

);

#上述操作报错,因为主表中的dept_id上没有主键约束或唯一性约束。
#③ 添加的表级约束
ALTER TABLE dept1
ADD PRIMARY KEY (dept_id);

DESC dept1;

#④ 再重新创建从表,因为上次引用主表的字段失败了
CREATE TABLE emp1(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(15),
department_id INT,

#表级约束
CONSTRAINT fk_emp1_dept_id FOREIGN KEY (department_id) REFERENCES dept1(dept_id)

);

DESC emp1;


SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'emp1';

演示外键的效果
#7.2 演示外键的效果
#添加失败.主表被引用的字段不存在
INSERT INTO emp1
VALUES(1001,'Tom',10);

# 在主表中添加数据
INSERT INTO dept1
VALUES(10,'IT');
#在主表dept1中添加了10号部门以后,我们就可以在从表中添加10号部门的员工

# 在从表中添加数据
INSERT INTO emp1
VALUES(1001,'Tom',10);

#删除失败。先删除主表的数据报错
DELETE FROM dept1
WHERE dept_id = 10;

#更新失败。更改主表的数据报错,因为从表还在引用这个数据
UPDATE dept1
SET dept_id = 20
WHERE dept_id = 10;

总结:约束关系是针对双方的
(1)添加了外键约束后,主表的修改和删除数据受约束
(2)添加了外键约束后,从表的添加和修改数据受约束
(3)在从表上建立外键,要求主表必须存在
(4)删除主表时,要求从表从表先删除,或将从表中外键引用该主表的关系先删除

在ALTER TABLE时添加外键约束
#7.3 在ALTER TABLE时添加外键约束
# 主表
CREATE TABLE dept2( 
dept_id INT PRIMARY KEY,
dept_name VARCHAR(15)
);

# 从表
CREATE TABLE emp2(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(15),
department_id INT
);

ALTER TABLE emp2
ADD CONSTRAINT fk_emp2_dept_id FOREIGN KEY(department_id) REFERENCES dept2(dept_id);

SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'emp2';
约束等级

(1)Cascade方式 :在父表上update/delete记录时,同步update/delete掉子表的匹配记录
(2)Set null方式 :在父表上update/delete记录时,将子表上匹配记录的列设为null,但是要注意子表的外键列不能为not null
(3)No action方式 :如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
(4)Restrict方式 :同no action, 都是立即检查外键约束
(5)Set default方式 (在可视化工具SQLyog中可能显示空白):父表有变更时,子表将外键列设置
成一个默认的值,但Innodb不能识别

尤其注意(1)(2),平时我们用的就是(3)(4)

casecade:级联。允许改主表被引用的字段,在改主表数据的同时,从表引用的字段自动修改

set null:允许主表删除一条记录,在删除的同时,从表引用字段的相应位置被设为null

#7.4 ###  约束等级

-- `Cascade方式`:在父表上update/delete记录时,同步update/delete掉子表的匹配记录 

-- `Set null方式`:在父表上update/delete记录时,将子表上匹配记录的列设为null,但是要注意子表的外键列不能为not null  

-- `No action方式`:如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作  

-- `Restrict方式`:同no action, 都是立即检查外键约束

-- `Set default方式`(在可视化工具SQLyog中可能显示空白):父表有变更时,子表将外键列设置成一个默认的值,但Innodb不能识别

#演示:
# on update cascade, on delete set null
CREATE TABLE dept(
    did INT PRIMARY KEY,		#部门编号
    dname VARCHAR(50)			#部门名称
);

CREATE TABLE emp(
    eid INT PRIMARY KEY,  #员工编号
    ename VARCHAR(5),     #员工姓名
    deptid INT,		  #员工所在的部门
    FOREIGN KEY (deptid) REFERENCES dept(did)  ON UPDATE CASCADE ON DELETE SET NULL
    #把修改操作设置为级联修改等级,把删除操作设置为set null等级
);
# 主表加数据
INSERT INTO dept VALUES(1001,'教学部');
INSERT INTO dept VALUES(1002, '财务部');
INSERT INTO dept VALUES(1003, '咨询部');

# 从表加数据
INSERT INTO emp VALUES(1,'张三',1001); #在添加这条记录时,要求部门表有1001部门
INSERT INTO emp VALUES(2,'李四',1001);
INSERT INTO emp VALUES(3,'王五',1002);


UPDATE dept
SET did = 1004
WHERE did = 1002;

DELETE FROM dept
WHERE did = 1004;


SELECT * FROM dept;

SELECT * FROM emp;

#结论:对于外键约束,最好是采用: `ON UPDATE CASCADE ON DELETE RESTRICT` 的方式。
# 主表更新可以更新,但是删除最好不要允许直接删除
删除外键约束
#7.5 删除外键约束

#一个表中可以声明有多个外键约束
USE atguigudb;
SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'employees';

USE dbtest13;

SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'emp1';

#删除外键约束

ALTER TABLE emp1
DROP FOREIGN KEY fk_emp1_dept_id;

#再手动的删除外键约束对应的普通索引
# 先看有哪些索引
SHOW INDEX FROM emp1;

ALTER TABLE emp1
DROP INDEX fk_emp1_dept_id;
开发场景

问题1:如果两个表之间有关系(一对一、一对多),比如:员工表和部门表(一对多),它们之间是否一定要建外键约束?
答:不是的

问题2:建和不建外键约束有什么区别?
答:建外键约束,你的操作(创建表、删除表、添加、修改、删除)会受到限制,从语法层面受到限制。例如:在员工表中不可能添加一个员工信息,它的部门的值在部门表中找不到。不建外键约束,你的操作(创建表、删除表、添加、修改、删除)不受限制,要保证数据的 引用完整性 ,只能依靠程序员的自觉 ,或者是 在Java程序中进行限定 。例如:在员工表中,可以添加一个员工的
信息,它的部门指定为一个完全不存在的部门。

问题3:那么建和不建外键约束和查询有没有关系?
答:没有

在 MySQL 里,外键约束是有成本的,需要消耗系统资源。对于大并发的 SQL 操作,有可能会不适合。比如大型网站的中央数据库,可能会 因为外键约束的系统开销而变得非常慢 。所以, MySQL 允许你不使用系统自带的外键约束,在 应用层面完成检查数据一致性的逻辑。也就是说,即使你不用外键约束,也要想办法通过应用层面的附加逻辑,来实现外键约束的功能,确保数据的一致性

阿里开发规范:不得使用外键与级联,一切外键概念必须在应用层解决

外键与级联更新适用于单机低并发 ,不适合分布式 、 高并发集群 ;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度

检查约束check

检查某个字段的值是否符号xx要求,一般指的是值的范围

mysql5.7不支持check约束,不会报错,只是没有作用

CREATE TABLE test10(
id INT,
last_name VARCHAR(15),
salary DECIMAL(10,2) CHECK(salary > 2000)
);

INSERT INTO test10
VALUES(1,'Tom',2500);

#添加失败
INSERT INTO test10
VALUES(2,'Tom1',1500);

SELECT * FROM test10;

默认值约束default

给某个字段/某列指定默认值,一旦设置默认值,在插入数据时,如果此字段没有显式赋值,则赋值为默认值

在CREATE TABLE添加约束
#9.1 在CREATE TABLE添加约束
CREATE TABLE test11(
id INT,
last_name VARCHAR(15),
salary DECIMAL(10,2) DEFAULT 2000
);

DESC test11;

INSERT INTO test11(id,last_name,salary)
VALUES(1,'Tom',3000);

INSERT INTO test11(id,last_name)
VALUES(2,'Tom1');

SELECT * FROM test11;
在ALTER TABLE添加约束
#9.2 在ALTER TABLE添加约束
CREATE TABLE test12(
id INT,
last_name VARCHAR(15),
salary DECIMAL(10,2)
);

DESC test12;

ALTER TABLE test12
MODIFY salary DECIMAL(8,2) DEFAULT 2500;
在ALTER TABLE删除约束
#9.3 在ALTER TABLE删除约束
ALTER TABLE test12
MODIFY salary DECIMAL(8,2);

# 查看数据表结构
SHOW CREATE TABLE test12;
应用场景

面试1、为什么建表时,加 not null default ‘’ 或 default 0
答:不想让表中出现null值。

面试2、为什么不想要 null 的值
答:(1)不好比较。null是一种特殊值,比较时只能用专门的is null 和 is not null来比较。碰到运算符,通常返回null。
(2)效率不高。影响提高索引效果。因此,我们往往在建表时 not null default ‘’ 或 default 0

面试3、带AUTO_INCREMENT约束的字段值是从1开始的吗
在MySQL中,默认AUTO_INCREMENT的初始值是1,每新增一条记录,字段值自动加1。设置自增属性(AUTO_INCREMENT)的时候,还可以指定第一条插入记录的自增字段的值,这样新插入的记录的自增字段值从初始值开始递增,如在表中插入第一条记录,同时指定id值为5,则以后插入的记录的id值就会从6开始往上增加。添加主键约束时,往往需要设置字段自动增加属性。

面试4、并不是每个表都可以任意选择存储引擎?
外键约束(FOREIGN KEY)不能跨引擎使用。MySQL支持多种存储引擎,每一个表都可以指定一个不同的存储引擎,需要注意的是:外键约束是用来保证数据的参照完整性的,如果表之间需要关联外键,却指定了不同的存储引擎,那么这些表之间是不能创建外键约束的。所以说,存储引擎的选择也不完全是随意的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值