第十三章、约束.sql 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. #第十三章、约束
  2. /*
  3. 1、基础知识
  4. 1.1、为什么需要约束?为了保证数据的完整性!
  5. 1.2、什么叫约束?对表中字段的限制。
  6. 1.3、约束的分类:
  7. 角度1:约束的字段的个数
  8. 单列约束 VS 多列约束
  9. 角度2:约束的作用范围
  10. 列级约束:将此约束声明在对应字段的后面
  11. 表级约束:在表中所有字段都声明完,在所有字段的后面声明的约束
  12. 角度3:约束的作用(或功能)
  13. (1)not null(非空约束)
  14. (2)unique(唯一性约束)
  15. (3)primary key(主键约束)
  16. (4)foreign key(外键约束)
  17. (5)check(检查约束)
  18. (6)default(默认值约束)
  19. 1.4、如何添加/删除约束?
  20. CREATE TABLE 时添加约束
  21. ALTER TABLE 时增加约束、删除约束
  22. */
  23. #2、如何查看表中的约束
  24. SELECT * FROM information_schema.TABLE_CONSTRAINTS
  25. WHERE table_name = '表名称';
  26. SELECT * FROM information_schema.TABLE_CONSTRAINTS
  27. WHERE table_name = 'employees';
  28. CREATE DATABASE dbtest13;
  29. USE dbtest13;
  30. #3、not null(非空约束)
  31. #3.1、在CREATE TABLE时添加约束
  32. CREATE TABLE test1(
  33. id INT NOT NULL,
  34. last_name VARCHAR(15) NOT NULL,
  35. email VARCHAR(25),
  36. salary DECIMAL(10,2)
  37. );
  38. DESC test1;
  39. SELECT * FROM information_schema.TABLE_CONSTRAINTS
  40. WHERE table_name = 'test1';
  41. INSERT INTO test1(id,last_name,email,salary)
  42. VALUES(1,'Tom','Tom@126.com',3400);
  43. #Column 'last_name' cannot be null
  44. INSERT INTO test1(id,last_name,email,salary)
  45. VALUES(2,NULL,'Tom@126.com',3400);
  46. #Column 'id' cannot be null
  47. INSERT INTO test1(id,last_name,email,salary)
  48. VALUES(NULL,'Jerry','Jerry@126.com',3400);
  49. INSERT INTO test1(id,email)
  50. VALUES(2,'abc@126.com');
  51. UPDATE test1
  52. SET email = NULL
  53. WHERE id = 1;
  54. UPDATE test1
  55. SET last_name = NULL
  56. WHERE id = 1;
  57. UPDATE test1
  58. SET email = 'Tom@126.com'
  59. WHERE id = 1;
  60. #3.2、在ALTER TABLE时添加约束
  61. ALTER TABLE test1
  62. MODIFY email VARCHAR(25) NOT NULL;
  63. DESC test1;
  64. #3.3、在ALTER TABLE时删除约束
  65. ALTER TABLE test1
  66. MODIFY email VARCHAR(25) NULL;
  67. #4、unique(唯一性约束)
  68. #4.1、在CREATE TABLE时添加约束
  69. CREATE TABLE test2(
  70. id INT UNIQUE, #列级约束
  71. last_name VARCHAR(15),
  72. email VARCHAR(25),
  73. salary DECIMAL(10,2),
  74. #表级约束
  75. CONSTRAINT uk_test2_email UNIQUE(email)
  76. );
  77. DESC test2;
  78. SELECT * FROM information_schema.TABLE_CONSTRAINTS
  79. WHERE table_name = 'test2';
  80. #在创建唯一约束的时候,如果不给唯一约束命名,就默认和列名相同。
  81. INSERT INTO test2(id,last_name,email,salary)
  82. VALUES(1,'Tom','Tom@126.com',4500);
  83. #错误:Duplicate entry '1' for key 'test2.id'
  84. INSERT INTO test2(id,last_name,email,salary)
  85. VALUES(1,'Tom1','Tom1@126.com',4600);
  86. #错误:Duplicate entry 'Tom@126.com' for key 'test2.uk_test2_email'
  87. INSERT INTO test2(id,last_name,email,salary)
  88. VALUES(2,'Tom1','Tom@126.com',4600);
  89. #可以向声明为UNIQUE的字段上添加NULL值。
  90. INSERT INTO test2(id,last_name,email,salary)
  91. VALUES(2,'Tom1',NULL,4600);
  92. INSERT INTO test2(id,last_name,email,salary)
  93. VALUES(3,'Tom2',NULL,4600);
  94. SELECT * FROM test2;
  95. #4.2、在ALTER TABLE时添加约束
  96. DESC test2;
  97. UPDATE test2
  98. SET salary = 5000
  99. WHERE id = 3;
  100. #方式一
  101. ALTER TABLE test2
  102. ADD CONSTRAINT uk_test2_sal UNIQUE(salary);
  103. #方式二
  104. ALTER TABLE test2
  105. MODIFY last_name VARCHAR(15) UNIQUE;
  106. #4.3、复合的唯一性约束
  107. CREATE TABLE USER(
  108. id INT,
  109. `name` VARCHAR(15),
  110. `password` VARCHAR(25),
  111. CONSTRAINT uk_user_name_ped UNIQUE(`name`,`password`)
  112. );
  113. INSERT INTO USER
  114. VALUES(1,'Tom','abc');
  115. #可以添加成功
  116. INSERT INTO USER
  117. VALUES(1,'Tom1','abc');
  118. SELECT * FROM USER;
  119. #案例:复合的唯一性约束的案例
  120. #学生表
  121. CREATE TABLE student(
  122. sid INT, #学号
  123. sname VARCHAR(20), #姓名
  124. tel CHAR(11), #电话
  125. cardid CHAR(18) #身份证号
  126. );
  127. #课程表
  128. CREATE TABLE course(
  129. cid INT, #课程编号
  130. cname VARCHAR(20) #课程名称
  131. );
  132. #选课表
  133. CREATE TABLE student_course(
  134. id INT,
  135. sid INT, #学号
  136. cid INT, #课程编号
  137. score INT,
  138. UNIQUE KEY(sid,cid) #复合唯一
  139. );
  140. INSERT INTO student
  141. VALUES(1,'张三','13710011002','101223199012015623');
  142. INSERT INTO student
  143. VALUES(2,'李四','13710011003','101223199012015624');
  144. INSERT INTO course
  145. VALUES(1001,'Java'),('1002','MySQL');
  146. SELECT * FROM student;
  147. SELECT * FROM course;
  148. INSERT INTO student_course VALUES
  149. (1,1,1001,89),
  150. (2,1,1002,90),
  151. (3,2,1001,88),
  152. (4,2,1002,56);
  153. SELECT * FROM student_course;
  154. #错误:Duplicate entry '2-1002' for key 'student_course.sid'
  155. INSERT INTO student_course VALUES
  156. (5,2,1002,67);
  157. #4.4、删除唯一性约束
  158. --  添加唯一性约束的列上也会自动创建唯一索引。
  159. --  删除唯一约束只能通过删除唯一索引的方式删除。
  160. --  删除时需要指定唯一索引名,唯一索引名就和唯一约束名一样。
  161. --  如果创建唯一约束时未指定名称,如果是单列,就默认和列名相同;如果是组合列,那么默认和()中排在第一个的列名相同。也可以自定义唯一性约束名。
  162. SELECT * FROM information_schema.TABLE_CONSTRAINTS
  163. WHERE table_name = 'test2';
  164. DESC test2;
  165. #如何删除唯一性索引
  166. ALTER TABLE test2
  167. DROP INDEX last_name;
  168. ALTER TABLE test2
  169. DROP INDEX uk_test2_sal;
  170. SHOW INDEX FROM test2;
  171. #5、primary key(主键约束)
  172. #5.1、在CREATE TABLE时添加约束
  173. #一个表中最多只能有一个主键约束
  174. #错误:Multiple primary key defined
  175. CREATE TABLE test3(
  176. id INT PRIMARY KEY, #列级约束
  177. last_name VARCHAR(15) PRIMARY KEY,
  178. salary DECIMAL(10,2),
  179. email VARCHAR(25)
  180. );
  181. #主键约束特征:非空且唯一,用于唯一的标识表中的一条记录。
  182. CREATE TABLE test4(
  183. id INT PRIMARY KEY, #列级约束
  184. last_name VARCHAR(15),
  185. salary DECIMAL(10,2),
  186. email VARCHAR(25)
  187. );
  188. #MySQL的主键名总是PRIMARY,就算自己命名了主键约束名也没用
  189. CREATE TABLE test5(
  190. id INT,
  191. last_name VARCHAR(15),
  192. salary DECIMAL(10,2),
  193. email VARCHAR(25),
  194. #表级约束
  195. CONSTRAINT pk_test5_id PRIMARY KEY(id) #没有必要起名字
  196. );
  197. SELECT* FROM information_schema.TABLE_CONSTRAINTS
  198. WHERE table_name = 'test5';
  199. INSERT INTO test4(id,last_name,salary,email)
  200. VALUES(1,'Tom',4500,'Tom@126.com');
  201. INSERT INTO test4(id,last_name,salary,email)
  202. VALUES(1,'Tom1',4600,'Tom1@126.com');
  203. INSERT INTO test4(id,last_name,salary,email)
  204. VALUES(NULL,'Tom2',4700,'Tom2@126.com');
  205. #如果是多列组合的复合主键约束,那么这些列都不允许为空值,并且组合的值不允许重复
  206. CREATE TABLE user1(
  207. id INT,
  208. name VARCHAR(15),
  209. password VARCHAR(25),
  210. PRIMARY KEY(name,password)
  211. );
  212. INSERT INTO user1
  213. VALUES(1,'Tom','abc');
  214. INSERT INTO user1
  215. VALUES(1,'Tom1','abc');
  216. #错误:Column 'name' cannot be null
  217. INSERT INTO user1
  218. VALUES(1,NULL,'abc');
  219. SELECT * FROM user1;
  220. #5.2、在ALTER TABLE时添加约束
  221. CREATE TABLE test6(
  222. id INT,
  223. last_name VARCHAR(15),
  224. salary DECIMAL(10,2),
  225. email VARCHAR(25)
  226. );
  227. ALTER TABLE test6
  228. ADD PRIMARY KEY(id);
  229. DESC test6;
  230. #5.3、如何删除主键约束(实际开发中,不会去删除表中的主键约束!)
  231. ALTER TABLE test6
  232. DROP PRIMARY KEY;
  233. #6、自增长列:AUTO_INCREMENT
  234. #6.1、在CREATE TABLE时添加
  235. #错误情况一:
  236. CREATE TABLE test7(
  237. id INT AUTO_INCREMENT,
  238. last_name VARCHAR(15)
  239. );
  240. #错误情况二
  241. CREATE TABLE test7(
  242. id INT,
  243. last_name VARCHAR(15) UNIQUE AUTO_INCREMENT
  244. );
  245. #正确的
  246. CREATE TABLE test7(
  247. id INT PRIMARY KEY AUTO_INCREMENT,
  248. last_name VARCHAR(15)
  249. );
  250. #开发中,一旦主键作用的字段上声明有AUTO_INCREMENT,则我们在添加数据时,就不要给主键对应的字段去赋值了。
  251. INSERT INTO test7(last_name)
  252. VALUES('Tom');
  253. SELECT * FROM test7;
  254. #当我们向主键(含AUTO_INCREMENT)的字段上添加0或NULL时,实际上会自动的往上添加指定的字段的数值
  255. INSERT INTO test7(id,last_name)
  256. VALUES(0,'Tom');
  257. INSERT INTO test7(id,last_name)
  258. VALUES(NULL,'Tom');
  259. INSERT INTO test7(id,last_name)
  260. VALUES(10,'Tom');
  261. INSERT INTO test7(id,last_name)
  262. VALUES(-10,'Tom');
  263. #6.2、在ALTER TABLE时添加
  264. CREATE TABLE test8(
  265. id INT PRIMARY KEY,
  266. last_name VARCHAR(15)
  267. );
  268. DESC test8;
  269. ALTER TABLE test8
  270. MODIFY id INT AUTO_INCREMENT;
  271. #6.2、在ALTER TABLE时删除
  272. ALTER TABLE test8
  273. MODIFY id INT;
  274. #6.3、MySQL8.0新特性——自增变量的持久化
  275. CREATE TABLE test9(
  276. id INT PRIMARY KEY AUTO_INCREMENT
  277. );
  278. INSERT INTO test9
  279. VALUES(0),(0),(0),(0);
  280. SELECT * FROM test9;
  281. DELETE FROM test9
  282. WHERE id = 4;
  283. INSERT INTO test9
  284. VALUES(0);
  285. DELETE FROM test9
  286. WHERE id = 5;
  287. #重启服务器
  288. SELECT * FROM test9;
  289. INSERT INTO test9
  290. VALUES(0);
  291. INSERT INTO test9
  292. VALUES(5);
  293. #7、foreign key(外键约束)
  294. #7.1、在ALTER TABLE时添加
  295. #主表和从表:父表和子表
  296. #(1)先创建主表
  297. CREATE TABLE dept1(
  298. dept_id INT,
  299. dept_name VARCHAR(15)
  300. );
  301. #(2)再创建从表
  302. CREATE TABLE emp1(
  303. emp_id INT PRIMARY KEY AUTO_INCREMENT,
  304. emp_name VARCHAR(15),
  305. department_id INT,
  306. #表级约束
  307. CONSTRAINT fk_emp1_dept_id FOREIGN KEY(department_id) REFERENCES dept1(dept_id)
  308. );
  309. #上述操作报错,因为主表中的dept_id上没有主键约束或唯一性约束。
  310. #(3)添加
  311. ALTER TABLE dept1
  312. ADD PRIMARY KEY(dept_id);
  313. DESC dept1;
  314. #(4)再创建从表
  315. CREATE TABLE emp1(
  316. emp_id INT PRIMARY KEY AUTO_INCREMENT,
  317. emp_name VARCHAR(15),
  318. department_id INT,
  319. #表级约束
  320. CONSTRAINT fk_emp1_dept_id FOREIGN KEY(department_id) REFERENCES dept1(dept_id)
  321. );
  322. DESC emp1;
  323. SELECT * FROM information_schema.TABLE_CONSTRAINTS
  324. WHERE table_name = 'emp1';
  325. #7.2、演示外键的效果
  326. #添加失败
  327. INSERT INTO emp1
  328. VALUES(1001,'Tom',10);
  329. INSERT INTO dept1
  330. VALUES(10,'IT');
  331. #在主表dept1中添加了10号部门以后,我们就可以在从表在添加10号部门的员工
  332. INSERT INTO emp1
  333. VALUES(1001,'Tom',10);
  334. #删除失败
  335. DELETE FROM dept1
  336. WHERE dept_id = 10;
  337. #更新失败
  338. UPDATE dept1
  339. SET dept_id = 20
  340. WHERE dept_id = 10;
  341. #7.3、在ALTER TABLE时添加外键约束
  342. CREATE TABLE dept2(
  343. dept_id INT PRIMARY KEY,
  344. dept_name VARCHAR(15)
  345. );
  346. CREATE TABLE emp2(
  347. emp_id INT PRIMARY KEY AUTO_INCREMENT,
  348. emp_name VARCHAR(15),
  349. department_id INT
  350. );
  351. ALTER TABLE emp2
  352. ADD CONSTRAINT fk_emp2_dept_id FOREIGN KEY(department_id) REFERENCES dept2(dept_id);
  353. SELECT * FROM information_schema.TABLE_CONSTRAINTS
  354. WHERE table_name = 'emp2';
  355. #7.4、约束等级
  356. --  Cascade方式:在父表上update/delete记录时,同步update/delete掉子表的匹配记录
  357. -- Set null方式:在父表上update/delete记录时,将子表上匹配记录的列设为null,
  358. -- 但是要注意子表的外键列不能为not null
  359. -- No action方式:如果子表中有匹配的记录,则不允许对父表对应候选键
  360. -- 进行update/delete操作
  361. -- Restrict方式:同no action,都是立即检查外键约束
  362. -- Set default方式(在可视化工具SQLyog中可能显示空白):父表有变更时,
  363. -- 子表将外键列设置成一个默认的值,但InnoDB不能识别
  364. #演示:ON UPDATE CASCADE ON DELETE RESTRICT
  365. CREATE TABLE dept(
  366. did INT PRIMARY KEY, #部门编号
  367. dname VARCHAR(50) #部门名称
  368. );
  369. CREATE TABLE emp(
  370. eid INT PRIMARY KEY, #员工编号
  371. ename VARCHAR(5), #员工姓名
  372. deptid INT, #员工所在部门
  373. FOREIGN KEY(deptid) REFERENCES dept(did) ON UPDATE CASCADE ON DELETE SET NULL
  374. #把修改操作设置为级联修改等级,把删除操作设置为set null等级
  375. );
  376. INSERT INTO dept VALUES(1001,'教学部');
  377. INSERT INTO dept VALUES(1002,'财务部');
  378. INSERT INTO dept VALUES(1003,'咨询部');
  379. INSERT INTO emp VALUES(1,'张三',1001);
  380. INSERT INTO emp VALUES(2,'李四',1001);
  381. INSERT INTO emp VALUES(3,'王五',1002);
  382. UPDATE dept
  383. SET did = 1004
  384. WHERE did = 1002;
  385. DELETE FROM dept
  386. WHERE did = 1004;
  387. SELECT * FROM dept;
  388. SELECT * FROM emp;
  389. #结论:对于外键约束,最好是采用:ON UPDATE CASCADE ON DELETE RESTRICT的方式。
  390. #7.5、删除外键约束
  391. #一个表中可以声明有多个外键约束
  392. SELECT * FROM information_schema.TABLE_CONSTRAINTS
  393. WHERE table_name = 'emp1';
  394. #删除外键约束
  395. ALTER TABLE emp1
  396. DROP FOREIGN KEY fk_emp1_dept_id;
  397. #再手动的删除外键约束对应的普通索引
  398. SHOW INDEX FROM emp1;
  399. ALTER TABLE emp1
  400. DROP INDEX fk_emp1_dept_id;
  401. #8、check约束
  402. #MySQL5.7 不支持CHECK约束,MySQL8.0 支持CHECK约束
  403. CREATE TABLE test10(
  404. id INT,
  405. last_name VARCHAR(15),
  406. salary DECIMAL(10,2) CHECK(salary > 2000)
  407. );
  408. INSERT INTO test10
  409. VALUES(1,'Tom',2500);
  410. #添加失败
  411. INSERT INTO test10
  412. VALUES(2,'Tom1',1500);
  413. SELECT * FROM test10;
  414. #9、DEFAULT约束
  415. #9.1、在CREATE TABLE添加约束
  416. CREATE TABLE test11(
  417. id INT,
  418. last_name VARCHAR(15),
  419. salary DECIMAL(10,2) DEFAULT 2000
  420. );
  421. DESC test11;
  422. INSERT INTO test11(id,last_name,salary)
  423. VALUES(1,'Tom',3000);
  424. INSERT INTO test11(id,last_name)
  425. VALUES(2,'Tom');
  426. SELECT * FROM test11;
  427. #9.2、在ALTER TABLE添加约束
  428. CREATE TABLE test12(
  429. id INT,
  430. last_name VARCHAR(15),
  431. salary DECIMAL(10,2)
  432. );
  433. DESC test12;
  434. ALTER TABLE test12
  435. MODIFY salary DECIMAL(8,2) DEFAULT 2500;
  436. #9.3、在ALTER TABLE删除约束
  437. ALTER TABLE test12
  438. MODIFY salary DECIMAL(8,2);