1、基础

  1. 登录数据库系统
mysql -h localhost -u root -p

#“-h”参数指连接的主机名
#“-u”参数表示用户名
#“-p”参数表示用户的密码
  1. 创建数据库
create database <db-name>;
  1. 查看数据库
show databases;
  1. 切换数据库
USE 数据库名;
  1. 删除数据库
drop database <db-name>;
  1. 创建新表
create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)

约束条件表:

约束条件

说明

PRIMARY KEY

标识该属性为该表的主键,可以唯一的标识对应的元组

FOREIGN KEY

标识该属性为该表的外键,是与之联系某表的主键

NOT NULL

标识该属性不能为空

UNIQUE

标识该属性的值是唯一的

AUTO_INCREMENT

标识该属性的值是自动增加,这是MySQL的SQL语句的特色

DEFAULT

为该属性设置默认值

  • 创建新表
create table course_class (course_id int UNSIGNED AUTO_INCREMENT, class_name varchar(20) not null,teacher_name varchar(20) not null,insert_time timestamp not null default current_timestamp COMMENT '插入时间',primary key(`course_id`));

# UNSIGNED AUTO_INCREMENT 插入数据时,索引自动+1
# primary key(`course_id`)主键约束
  • 删除表
drop table table_name;
  • 使用旧表创建新表
create table tab_new like tab_old
  1. 查看表结构
desc <table-name>;
  1. 修改表名
ALTER TABLE 旧表名 RENAME 新表名;
  1. 修改字段的数据类型
ALTER TABLE 表名 MODIFY 字段名 数据类型;

ALTER TABLE student MODIFY name varchar(30);
  1. 修改字段名
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型;

ALTER TABLE student1 CHANGE name stu_name varchar(40);
  1. 增加字段
ALTER TABLE 表名 ADD 字段名1 数据类型 [完整性约束条件] [FIRST | AFTER 字段名2];

ALTER TABLE student1 ADD teacher_name varchar(20) NOT NULL AFTER id;
  1. 删除字段
ALTER TABLE 表名 DROP 字段名;

ALTER TABLE student DROP stu_name;
  1. 删除表的外键约束
ALTER TABLE 表名 DROP FOREIGN KEY 外键别名;

ALTER TABLE teacher DROP FOREIGN KEY STUID;

删除被其他表关联的父表:

方法一:先删除子表,在删除父表

方法二:删除父表的外键约束(上面有介绍),再删该表

  1. 删除表的主键约束
Alter table tabname drop primary key(col)
  1. 添加主键
Alter table tabname add primary key(col)
  1. 创建索引
create [unique] index idxname on tabname(col….) 

# 删除索引

drop index idxname
#注:索引是不可更改的,想更改必须删除重新建。
  1. 创建视图
create view viewname as select statement 

# 删除视图
drop view viewname
  1. 数据库存储引擎
# 查看
SHOW ENGINES;

# 修改
ALTER TABLE 表名 ENGINE = 存储引擎名;

2、增删改查

2.1 基本查询语句

选择
select * from table1 where 范围

# 指定数据库
select * from database_name.table1 where 范围;
插入
insert into table1(field1,field2) values(value1,value2)
删除
delete from table1 where 范围
更新
update table1 set field1=value1 where 范围
查找
select * from table1 where field1 like ’%value1%’
排序
select * from table1 order by field1,field2 [desc]
总数
select count as totalcount from table1
求和
select sum(field1) as sumvalue from table1
平均
select avg(field1) as avgvalue from table1
最大
select max(field1) as maxvalue from table1
最小
select min(field1) as minvalue from table1

2.2 高级查询运算词

UNION 运算符

UNION 运算符通过组合其他两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重复行而派生出一个结果表。当 ALL 随 UNION 一起使用时(即 UNION ALL),不消除重复行。两种情况下,派生表的每一行不是来自 TABLE1 就是来自 TABLE2。

EXCEPT 运算符

EXCEPT运算符通过包括所有在 TABLE1 中但不在 TABLE2 中的行并消除所有重复行而派生出一个结果表。当 ALL 随 EXCEPT 一起使用时 (EXCEPT ALL),不消除重复行。

INTERSECT 运算符

INTERSECT运算符通过只包括 TABLE1 和 TABLE2 中都有的行并消除所有重复行而派生出一个结果表。当 ALL随 INTERSECT 一起使用时 (INTERSECT ALL),不消除重复行。
**注:**使用运算词的几个查询结果行必须是一致的。

2.3 外连接

left (outer) join
左外连接(左连接):结果集几包括连接表的匹配行,也包括左连接表的所有行。 
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
right (outer) join
右外连接(右连接):结果集既包括连接表的匹配连接行,也包括右连接表的所有行。
full/cross (outer) join

全外连接:不仅包括符号连接表的匹配行,还包括两个连接表中的所有记录。

2.4 分组 Group by

一张表,一旦分组 完成后,查询后只能得到组相关的信息;将查询结果按照1个或多个字段进行分组,字段值相同的为一组;其实就是按照某一列进行分类;

group by单独使用时,只显示出每一组的第一条记录,所以group by单独使用时的实际意义不大

语法:

select 查询列表

from 表

[where 筛选条件]

group by 分组的字段

[order by 排序的字段];

特点:

1、和分组函数一同查询的字段必须是group by后出现的字段,也就是说group by后面接的字段必须在查询字段里;

2、筛选分为两类:分组前筛选和分组后筛选

分组前筛选: 原始表 位置在: group by前 连接关键字: where

分组后筛选: group by(分组后的结果集) 位置在:group by后 连接关键字: having

聚合函数:(统计信息):

  • count():统计记录的条数
  • sum():计算字段值的总和
  • avg():计算字段值的平均值
  • max():查询字段的最大值
  • min():查询字段的最小值

(1)单独使用 GROUP BY关键字时,查询结果会只显示每个分组的第一条记录。

(2)GROUP BY 关键字可以和 GROUP_CONCAT() 函数一起使用。GROUP_CONCAT() 函数会把每个分组的字段值都显示出来。

(3)group by + having

  • 用来分组查询后制定一些条件来输出查询结果
  • having的作用和where一样,但having只能用于group by
  • 查询工资总和大于9000的部门名称以及工资和
# 先将工资和大于9000的员工先查出来,再做分组
SELECT department,GROUP_CONCAT(salary),SUM(salary) FROM employee
GROUP BY department HAVING SUM(salary) > 9000;
  • havingwhere的区别:
  • having是在分组后对数据进行过滤
  • where是在分组前对数据进行过滤
  • having后面可以使用分组函数(统计函数)
  • where后面不可以使用分组函数
  • where是对分组前记录的条件,如果某行记录没有满足where子句的条件,那么这行记录不会参加分组;而having是对分组后数据的约束
  • 查询工资和大于2000的 工资总和大于6000的部门名称以及工资和
SELECT department,GROUP_CONCAT(salary).SUM(salary) FROM employee
WHERE salary > 2000
GROUP BY department
HAVING SUNM(salary) > 9000
ORDER BY SUM(salary) DESC;
//降序排列
SELECT `sex`, GROUP_CONCAT(name) FROM tb_students_info GROUP BY sex;
SELECT age,sex,GROUP_CONCAT(name) FROM tb_students_info GROUP BY age,sex;

# 查询每个工种的员工平均工资

SELECT AVG(salary),job_id FROM employees GROUP BY job_id;

# 查询每个位置的部门个数
SELECT COUNT(*),location_id FROM departments GROUP BY location_id;

# 分组前筛选
# 查询邮箱中包含a字符的 每个部门的最高工资
SELECT MAX(salary),department_id FROM employees WHERE email LIKE '%a%' GROUP BY department_id;

# 查询有奖金的每个领导手下员工的平均工资
SELECT AVG(salary),manager_id FROM employees WHERE commission_pct IS NOT NULL GROUP BY manager_id;

# 分组后筛选
# 查询哪个部门的员工个数>5
-- 1、查询每个部门的员工个数
SELECT COUNT(*),department_id FROM employees GROUP BY department_id;
-- 2、筛选上面的结果
SELECT COUNT(*),department_id FROM employees GROUP BY department_id HAVING COUNT(*)>5;

# 每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
SELECT job_id,MAX(salary) FROM employees WHERE commission_pct IS NOT NULL GROUP BY job_id HAVING MAX(salary)>12000;

# 领导编号>102的每个领导手下的最低工资大于5000的领导编号和最低工资manager_id>102
SELECT manager_id,MIN(salary) FROM employees GROUP BY manager_id HAVING MIN(salary)>5000;

多个字段分组查询时,会先按照第一个字段进行分组。如果第一个字段中有相同的值,MySQL 才会按照第二个字段进行分组。如果第一个字段中的数据都是唯一的,那么 MySQL 将不再对第二个字段进行分组。

WITH POLLUP 关键字用来在所有记录的最后加上一条记录,这条记录是上面所有记录的总和,即统计记录数量。

SELECT sex,GROUP_CONCAT(name) FROM tb_students_info GROUP BY sex WITH ROLLUP;

2.5 排序 order by

语法:

ORDER BY {<列名> | <表达式> | <位置>} [ASC|DESC] #asc升序(默认)

2.6 Limit 要查几行记录

SELECT * FROM employee LIMIT 3,3;

# 从第三行开始 取三条数据(从0开始计数)
# limit 参数1,参数2;# 参数1:从哪一行开始查;参数2:一共要查几行

分页操作:

int curPage = 1; -- 当前页
int pageSize = 3; -- 每页多少条数据

-- 当前页为1,第一页从0开始 (1-1)*3=0
-- 当前页为2,第一页从3开始 (2-1)*3=3
-- 当前页为3,第一页从6开始 (3-1)*3=6
-- 当前页为4,第一页从9开始 (4-1)*3=9

select * from employee limit (curPage-1) * pageSize,pageSize;

3、高阶用法

子查询(嵌套查询)

注意: 第一次的查询结果可以作为第二次的查询的 条件 或者 表名 使用;

子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字. 还可以包含比较运算符:= 、 !=、> 、<等;

一条语句中可以有多个这样的子查询,在执行时,最里层括号(sql语句) 具有优先执行权; as 后面的表名称不能加引号(’’);

select a,b,c from a where a [not] IN (select d from b )
或者
select a,b,c from a where a [not] IN (1,2,3)

select * from (select * from a) as 别名;

关键字:ANY

假设any内部的查询语句返回的结果个数是三个,如:result1,result2,result3 ...

select ...from ... where a > any(...);
->
select ...from ... where a > result1 or a > result2 or a > result3;

关键字:ALL

ALL关键字与any关键字类似,只不过上面的or改成and。即:

select ...from ... where a > all(...);
->
select ...from ... where a > result1 and a > result2 and a > result3;

关键字:Some

some关键字和any关键字是一样的功能。所以:

select ...from ... where a > some(...);
->
select ...from ... where a > result1 or a > result2 or a > result3;

关键字:EXISTS

EXISTS 和 NOT EXISTS 子查询语法如下:

  SELECT ... FROM table WHERE  EXISTS (subquery)
# 该语法可以理解为:主查询(外部查询)会根据子查询验证结果(TRUE 或 FALSE)来决定主查询是否得以执行。

mysql> SELECT * FROM person
    -> WHERE EXISTS
    -> (SELECT * FROM dept WHERE did=5);

# 此处内层循环并没有查询到满足条件的结果,因此返回false,外层查询不执行。

# NOT EXISTS刚好与之相反

mysql> SELECT * FROM person 
    -> WHERE NOT EXISTS 
    -> (SELECT * FROM dept WHERE did=5);
# 当然,EXISTS关键字可以与其他的查询条件一起使用,条件表达式与EXISTS关键字之间用AND或者OR来连接,如下:

mysql> SELECT * FROM person 
    -> WHERE AGE >23 AND NOT EXISTS 
    -> (SELECT * FROM dept WHERE did=5);
# 注意:
EXISTS (subquery) 只返回 TRUE 或 FALSE,因此子查询中的 SELECT * 也可以是 SELECT 1 或其他,官方说法是实际执行时会忽略 SELECT 清单,因此没有区别。
外连接查询(表名1:a 表名2:b)
select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
between的用法

between限制查询数据范围时包括了边界值,not between不包括

select * from table1 where time between time1 and time2
select a,b,c, from table1 where a not between 数值1 and 数值2
两张关联表,删除主表中已经在副表中没有的信息
delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )
三表联查
select a.uid,a.uname,a.upsw,a.urealname,a.utel,a.uremark, b.rid,b.rname,b.rremark,c.deptid,c.deptname,c.deptremark

from table1 a,table2 b,table3 c where a.sems_role_rid=b.rid and a.udeptid=c.deptid

或者:

select a.uid,a.uname,a.upsw,a.urealname,a.utel,a.uremark, b.rid,b.rname,b.rremark,c.deptid,c.deptname,c.deptremark

from table1 a left join table2 b on  a.sems_role_rid=b.rid left join table3 c on a.udeptid=c.deptid
四表联查问题
select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....

4. 多表查询

4.1 多表连接的分类:

多表查询时,一定要找到两个表中相互关联的字段,并且作为条件使用;

内连接查询与多表联合查询的效果是一样的;

多表连接查询语法:

SELECT 字段列表
    FROM 表1  INNER|LEFT|RIGHT JOIN  表2
ON 表1.字段 = 表2.字段;
  • 内连接
    joininner join
  • 外连接
    left joinleft outer joinright joinright outer joinunion
  • 交叉连接
    cross join

4.2 示例分析

假设有两张表test_atest_b,将表当作一个集合,那么表中的记录就是集合中的一个元素;

首先我们先来新建这两张表:

create table test_a (id int UNSIGNED AUTO_INCREMENT, name varchar(120) not null,address varchar(120), primary key(`id`));
create table test_b (id int, age int not null,sex varchar(120), primary key(`id`));

然后插入数据:

insert into test_a (name, address) values('zhao','深圳');
insert into test_a (name, address) values('qian','深圳');
insert into test_a (name, address) values('sun','深圳');
insert into test_a (name, address) values('li','深圳');

insert into test_b (id, age, sex) values(2,18,'男');
insert into test_b (id, age, sex) values(3,23,'女');
insert into test_b (id, age, sex) values(4,20,'女');
insert into test_b (id, age, sex) values(5,21,'男');
insert into test_b (id, age, sex) values(6,21,'女');

mysql 数据库表导出sql过大 mysql导出sql语句_表名

mysql 数据库表导出sql过大 mysql导出sql语句_字段名_02

4.2.1 内连接

inner join 或者 join(等同于inner join:如果表中有至少一个匹配,则返回行)

select a.*,b.* from test_a a inner join test_b b on a.id = b.id;

mysql 数据库表导出sql过大 mysql导出sql语句_表名_03

或者

select a.*,b.* from test_a a join test_b b on a.id = b.id;

mysql 数据库表导出sql过大 mysql导出sql语句_字段名_04

应用场景:

mysql 数据库表导出sql过大 mysql导出sql语句_表名_05

满足某一个条件的A、B内部的数据,得到内部共有的数据,也就是指显示只符合条件的数据;

4.2.2 外连接
4.2.2.1 left join >> 左外连接

left join 等同left outer join

4.2.2.1.1 左外连接:left join

left join

即使右表中没有匹配,也从左表返回所有的行(取左并集)

注意:在某些数据库中,LEFT JOIN 称为 LEFT OUTER JOIN。

select a.*, b.* from test_a a left join test_b b on a.id = b.id;

mysql 数据库表导出sql过大 mysql导出sql语句_字段_06

或者

select a.*,b.* from test_a a left outer join test_b b on a.id = b.id;

mysql 数据库表导出sql过大 mysql导出sql语句_表名_07

查询结果如图,在test_b表不存在记录使用NULL进行填充;

mysql 数据库表导出sql过大 mysql导出sql语句_mysql 数据库表导出sql过大_08

如上图所示得到的是A所有数据,以及满足某一个条件的B的数据;

LEFT JOIN 关键字从左表(table_a)返回所有的行,即使右表(table_b)中没有匹配。如果右表中没有匹配,则结果为 NULL

4.2.2.2 left join + where B.column is null

[left join 等同 left outer join] + [where B.column is null]

select a.id a_id,a.name,b.age,b.id b_id from test_a a left join test_b b on a.id = b.id where b.id is null;

查询结果如下:

mysql 数据库表导出sql过大 mysql导出sql语句_字段名_09

应用场景:

mysql 数据库表导出sql过大 mysql导出sql语句_字段名_10

如上图所示得到的是A中的所有数据减去"与B满足同一条件 的数据",然后得到的A剩余数据;

4.2.2.3 right join >> 右外连接

right join 等同right outer join

4.2.2.3.1 右外连接:right join

right join

即使左表中没有匹配,也从右表返回所有的行(取右并集);

注意:在某些数据库中,RIGHT JOIN 称为 RIGHT OUTER JOIN。

select a.id a_id,a.name,b.id b_id,b.age from test_a a right join test_b b on a.id = b.id;

查询结果:

mysql 数据库表导出sql过大 mysql导出sql语句_表名_11

应用场景:

mysql 数据库表导出sql过大 mysql导出sql语句_mysql 数据库表导出sql过大_12

如图得到的是B所有数据,和满足某一条件的A的数据;

RIGHT JOIN 关键字从右表(table_b)返回所有的行,即使左表(table_a)中没有匹配。如果左表中没有匹配,则结果为 NULL。

4.2.2.4 right join + where A.column is null
select a.id a_id,a.name, b.id b_id,b.age from test_a a right join test_b b on a.id = b.id where a.id is null;

查询结果如图:

mysql 数据库表导出sql过大 mysql导出sql语句_mysql 数据库表导出sql过大_13

应用场景:

mysql 数据库表导出sql过大 mysql导出sql语句_mysql_14

如上图所示,得到的是B中的所有数据减去与A满足条件的数据,然后得到B剩余的数据;

4.2.2.5 full join >> 全连接查询

left join union right join 等同于 full join(注意:在mysql并不支持full join

full join:只要其中一个表中存在匹配,则返回行;

select a.id a_id,a.name, b.id b_id,b.age from test_a a left join test_b b on a.id = b.id union select a.id a_id,a.name, b.id b_id,b.age from test_a a right join test_b b on a.id = b.id;

查询结果如下图:

mysql 数据库表导出sql过大 mysql导出sql语句_mysql_15

应用场景:

union ,重复的记录会合并(操作符合并两个或多个 SELECT 语句的结果,并去除重复数据),如上图查询结果id >> 2、3、4

注意:

(1)UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT 语句中的列的顺序必须相同。

(2)默认UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。

(3)UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名

mysql 数据库表导出sql过大 mysql导出sql语句_字段名_16

满足某一条件的公共记录,以及自己独有的记录;

4.2.2.6 (left join + is null) union (right join+is null)
select a.id a_id,a.name,b.id b_id,b.age from test_a a left join test_b b on a.id = b.id where b.id is null union select a.id a_id,a.name,b.id b_id,b.age from test_a a right join test_b b on a.id = b.id where a.id is null;

(left join + is null) union (right join+is null)等同于full join + is null(注意:mysql并不支持)

查询结果如下图:

mysql 数据库表导出sql过大 mysql导出sql语句_表名_17

应用场景:

mysql 数据库表导出sql过大 mysql导出sql语句_mysql 数据库表导出sql过大_18

获取A和B都不满足条件的记录;

4.2.3 交叉连接(cross join)
(1)cross join

实际应用中还有这样一种情形,想得到A,B记录的排列组合,即笛卡儿积,这个就不好用集合和元素来表示了。需要用到cross join

笛卡尔乘积公式 : A表中数据条数 * B表中数据条数 = 笛卡尔乘积.

如果不加条件直接进行查询,则会出现以下效果,这种结果我们称之为 笛卡尔乘积;

select a.id a_id,a.name,b.id b_id,b.age from test_a a cross join test_b b;

查询结果如下图:

mysql 数据库表导出sql过大 mysql导出sql语句_mysql 数据库表导出sql过大_19

(2)cross join指定条件 (where)
select a.id a_id,a.name,b.id b_id,b.age from test_a a cross join test_b b where a.id = b.id;

查询结果如下图:

mysql 数据库表导出sql过大 mysql导出sql语句_字段_20

5. SQL逻辑查询语句执行顺序

mysql 数据库表导出sql过大 mysql导出sql语句_mysql 数据库表导出sql过大_21

SELECT DISTINCT <select_list>
FROM <left_table>
<join_type> JOIN <right_table>
ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>

6. 详细讲一下:外键约束

6.1 先提几个疑问?

6.1.1 问题1

什么是约束?

约束是一种限制,它通过对表的行或列的数据做出限制,来确保表的数据的完整性、唯一性;

6.1.2 问题2

假设有两张表persondept中,新员工可以没有部门吗?

或者

新员工可以添加一个不存在的部门吗?

6.1.3 如何解决以上的问题

简单的说,就是对两个表的关系进行一些约束 (即:froegin key).

foreign key 定义:就是表与表之间的某种约定的关系,由于这种关系的存在,能够让表与表之间的数据,更加的完整,关连性更强。

foreign key

(1)在创建表时,先创建被关联的表dept,才能创建关联表person

(2)在插入记录时,必须先插入被关联的表dept,才能插入关联表person

(3)更新与删除都需要考虑到关联与被关联的关系

6.1.4 示例
6.1.4.1 创建数据表时并创建外键约束
-- 被关联表
CREATE TABLE IF NOT EXISTS dept (
    id int notnull auto_increment PRIMARY KEY,
    name VARCHAR(50) not null COMMENT'说明'
) ENGINE=INNODB DEFAULT charset utf8;

-- 关联表
CREATE TABLE IF NOT EXISTS person(
    id int not null auto_increment PRIMARY KEY,
    name VARCHAR(50) not null,
    age TINYINT(4) null DEFAULT 0,
    sexenum('男','女') NOT NULL DEFAULT '男',
    salarydecimal(10,2) NULL DEFAULT '250.00',
    hire_date date NOT NULL,
    dept_id int(11) DEFAULT NULL,
   CONSTRAINT fk_did FOREIGN KEY(dept_id) REFERENCES dept(id) -- 添加外键约束
)ENGINE = INNODB DEFAULT charset utf8;
6.1.4.2 关联表以及被关联被插入数据
insert into dept(name) values ('技术部');
 
insert into person(name,age,sexenum,salarydecimal,hire_date,dept_id)  values
('alex', '28', '男', '53000.00', '2010-06-21', '1');
6.1.4.3 更新与删除都需要考虑到关联与被关联的关系
-- 1、先删除关联表person,再删除被关联表dept,准备重建
-- 2、重建: 新增功能,同步更新,同步删除

-- 被关联表
CREATE TABLE IF NOT EXISTS dept (
    id int notnull auto_increment PRIMARY KEY,
    name VARCHAR(50) not null COMMENT'说明'
) ENGINE=INNODB DEFAULT charset utf8;

-- 关联表
CREATE TABLE IF NOT EXISTS person(
    id int not null auto_increment PRIMARY KEY,
    name VARCHAR(50) not null,
    age TINYINT(4) null DEFAULT 0,
    sexenum('男','女') NOT NULL DEFAULT '男',
    salarydecimal(10,2) NULL DEFAULT '250.00',
    hire_date date NOT NULL,
    dept_id int(11) DEFAULT NULL,
    CONSTRAINT fk_did FOREIGN KEY(dept_id) REFERENCES dept(id) -- 添加外键约束
    on update cascade -- 同步更新
    on delete cascade -- 同步删除
)ENGINE = INNODB DEFAULT charset utf8;

-- 然后再去修改
update dept set id=12 where id=2;
6.1.4.4 已经创建表后,追加外键约束
#添加外键约束
ALTER table person add constraint fk_did FOREIGN key(dept_id) REFERENCES dept(did);
  
#删除外键约束
ALTER TABLE person drop FOREIGN key fk_did;

6.2 定义外键的条件

(1)外键对应的字段数据类型保持一致,且被关联的字段(即references指定的另外一个表的字段),必须保证唯一;

(2)所有tables的存储引擎必须是InnoDB类型;

(3)外键的约束4种类型: 1.RESTRICT 2. NO ACTION 3.CASCADE 4.SET NULL;

  • RESTRICT:同no action, 都是立即检查外键约束
  • NO ACTION:如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
  • CASCADE:在父表上update/delete记录时,同步update/delete掉子表的匹配记录
  • SET NULL:在父表上update/delete记录时,将子表上匹配记录的列设为null (要注意子表的外键列不能为not null)

(4)注意:

  • 如果需要外键约束,最好创建表同时创建外键约束;
  • 如果需要设置级联关系,删除时最好设置为 SET NULL;
  • 插入数据时,先插入主表中的数据,再插入从表中的数据;
  • 删除数据时,先删除从表中的数据,再删除主表中的数据。

6.3 其他约束类型

6.3.1 非空约束

关键字: NOT NULL ,表示 不可空. 用来约束表中的字段列

create table test_a(
       id int(10) not null primary key,
       name varchar(100) null
 );
6.3.2 主键约束

用于约束表中的一行,作为这一行的标识符,在一张表中通过主键就能准确定位到一行,因此主键十分重要。

create table test_b(
    id int(10) not null primary key
);

注意事项:

主键这一行的数据不能重复,也不能为空;

6.3.3 特殊主键:复合主键

主键不仅可以是表中的一列,也可以由表中的两列或多列来共同标识

create table test_c(
    id int(10) not null,
    name varchar(100) ,
    primary key(id,name)
);
6.3.4 唯一约束

关键字: UNIQUE, 比较简单,它规定一张表中指定的一列的值必须不能有重复值,即这一列每个值都是唯一的。

create table test_d(
    id int(10) not null,
    name varchar(255) ,
    unique id_name(id,name)
);
-- 添加唯一约束
alter table test_d add unique id_name(id,name);
-- 删除唯一约束
alter table test_d drop index id_name;

注意事项:

当INSERT语句新插入的数据和已有数据重复的时候,如果有UNIQUE约束,则INSERT失败;

6.3.5 默认值约束

关键字:DEFAULT

create table test_f(
    id int(10) not null primary key,
    name varchar(255) default '张三'   
);
-- 插入数据
INSERT into test_f(id) VALUES(1),(2);

注意事项:

INSERT语句执行时.,如果被DEFAULT约束的位置没有值,那么这个位置将会被DEFAULT的值填充;

6.4 表与表之间的联系

6.4.1 表关系分类
  • 一对一
  • 一对多(多对一)
  • 多对多
6.4.2 如何区分表与表之间是什么关系?

分析步骤:

  • 多对一 /一对多
  1. 站在左表的角度去看右表(情况一)
    如果左表中的一条记录,对应右表中多条记录.那么他们的关系则为 一对多 关系.约束关系为:左表普通字段, 对应右表foreign key 字段.

注意:如果左表与右表的情况反之.则关系为 多对一 关系.约束关系为:左表foreign key 字段, 对应右表普通字段.

  • 一对一
    2. 站在左表的角度去看右表(情况二)
    如果左表中的一条记录 对应 右表中的一条记录. 则关系为 一对一关系.
    约束关系为:左表foreign key字段上 添加唯一(unique)约束, 对应右表 关联字段.
    或者:右表foreign key字段上 添加唯一(unique)约束, 对应右表 关联字段.
  • 多对多
    3. 站在左表和右表同时去看(情况三)
    如果左表中的一条记录 对应 右表中的多条记录,并且右表中的一条记录同时也对应左表的多条记录. 那么这种关系 则 多对多 关系.
    这种关系需要定义一个这两张表的[关系表]来专门存放二者的关系
6.4.3 建立表关系
6.4.3.1 一对多关系

例如:一个人可以拥有多辆汽车,要求查询某个人拥有的所有车辆。

分析:人和车辆分别单独建表,那么如何将两个表关联呢?有个巧妙的方法,在车辆的表中加个外键字段(人的编号)即可。

(思路小结:’建两个表,一’方不动,’多’方添加一个外键字段)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZGITFX1l-1627752212064)(SQL语句大全.assets/image-20210728214646402.png)]

//建立人员表
CREATE TABLE people(
    id VARCHAR(12) PRIMARY KEY,
    sname VARCHAR(12),
    age INT,
    sex CHAR(1)
);
INSERT INTO people VALUES('H001','小王',27,'1');
INSERT INTO people VALUES('H002','小明',24,'1');
INSERT INTO people VALUES('H003','张慧',28,'0');
INSERT INTO people VALUES('H004','李小燕',35,'0');
INSERT INTO people VALUES('H005','王大拿',29,'1');
INSERT INTO people VALUES('H006','周强',36,'1');
 //建立车辆信息表
CREATE TABLE car(
    id VARCHAR(12) PRIMARY KEY,
    mark VARCHAR(24),
    price NUMERIC(6,2),
    pid VARCHAR(12),
    CONSTRAINT fk_people FOREIGN KEY(pid) REFERENCES people(id)
);
INSERT INTO car VALUES('C001','BMW',65.99,'H001');
INSERT INTO car VALUES('C002','BenZ',75.99,'H002');
INSERT INTO car VALUES('C003','Skoda',23.99,'H001');
INSERT INTO car VALUES('C004','Peugeot',20.99,'H003');
INSERT INTO car VALUES('C005','Porsche',295.99,'H004');
INSERT INTO car VALUES('C006','Honda',24.99,'H005');
INSERT INTO car VALUES('C007','Toyota',27.99,'H006');
INSERT INTO car VALUES('C008','Kia',18.99,'H002');
INSERT INTO car VALUES('C009','Bentley',309.99,'H005');

-- 示例:班级和学生之间的关系
6.4.3.2 一对一关系

例如:一个中国公民只能有一个身份证信息

分析: 一对一的表关系实际上是 变异了的 一对多关系. 通过在从表的外键字段上添加唯一约束(unique)来实现一对一表关系.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HXvfgrOS-1627752212065)(SQL语句大全.assets/image-20210728214914347.png)]

#身份证信息表
CREATE TABLE card (
  id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  code varchar(18) DEFAULT NULL,
  UNIQUE un_code (CODE) -- 创建唯一索引的目的,保证身份证号码同样不能出现重复
);

INSERT INTO card VALUES(null,'210123123890890678'),
                       (null,'210123456789012345'),
                       (null,'210098765432112312');

#公民表
CREATE TABLE people (
  id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  name varchar(50) DEFAULT NULL,
  sex char(1) DEFAULT '0',
  c_id int UNIQUE, -- 外键添加唯一约束,确保一对一
  CONSTRAINT fk_card_id FOREIGN KEY (c_id) REFERENCES card(id)
);

INSERT INTO people VALUES(null,'zhangsan','1',1),
                         (null,'lisi','0',2),
                         (null,'wangwu','1',3);
6.4.3.3 多对多

例如:学生选课,一个学生可以选修多门课程,每门课程可供多个学生选择。

分析:这种方式可以按照类似一对多方式建表,但冗余信息太多,好的方式是实体和关系分离并单独建表,实体表为学生表和课程表,关系表为选修表,
其中关系表采用联合主键的方式(由学生表主键和课程表主键组成)建表。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X4SZZVWx-1627752212066)(SQL语句大全.assets/image-20210728215011801.png)]

#//建立学生表
CREATE TABLE student(
    id VARCHAR(10) PRIMARY KEY,
    sname VARCHAR(12),
    age INT,
    sex CHAR(1)
);
INSERT INTO student VALUES('S0001','王军',20,1);
INSERT INTO student VALUES('S0002','张宇',21,1);
INSERT INTO student VALUES('S0003','刘飞',22,1);
INSERT INTO student VALUES('S0004','赵燕',18,0);
INSERT INTO student VALUES('S0005','曾婷',19,0);
INSERT INTO student VALUES('S0006','周慧',21,0);
INSERT INTO student VALUES('S0007','小红',23,0);
INSERT INTO student VALUES('S0008','杨晓',18,0);
INSERT INTO student VALUES('S0009','李杰',20,1);
INSERT INTO student VALUES('S0010','张良',22,1);

# //建立课程表
CREATE TABLE course(
    id VARCHAR(10) PRIMARY KEY,
    sname VARCHAR(12),
    credit DOUBLE(2,1),
    teacher VARCHAR(12)
);
INSERT INTO course VALUES('C001','Java',3.5,'李老师');
INSERT INTO course VALUES('C002','高等数学',5.0,'赵老师');
INSERT INTO course VALUES('C003','JavaScript',3.5,'王老师');
INSERT INTO course VALUES('C004','离散数学',3.5,'卜老师');
INSERT INTO course VALUES('C005','数据库',3.5,'廖老师');
INSERT INTO course VALUES('C006','操作系统',3.5,'张老师');

# //建立选修表
CREATE TABLE sc(
    sid VARCHAR(10),
    cid VARCHAR(10),
      PRIMARY KEY(sid,cid),
      CONSTRAINT fk_student FOREIGN KEY(sid) REFERENCES student(id),
      CONSTRAINT fk_course FOREIGN KEY(cid) REFERENCES course(id)
);

INSERT INTO sc VALUES('S0001','C001');
INSERT INTO sc VALUES('S0001','C002');
INSERT INTO sc VALUES('S0001','C003');
INSERT INTO sc VALUES('S0002','C001');
INSERT INTO sc VALUES('S0002','C004');
INSERT INTO sc VALUES('S0003','C002');
INSERT INTO sc VALUES('S0003','C005');
INSERT INTO sc VALUES('S0004','C003');
INSERT INTO sc VALUES('S0005','C001');
INSERT INTO sc VALUES('S0006','C004');
INSERT INTO sc VALUES('S0007','C002');
INSERT INTO sc VALUES('S0008','C003');
INSERT INTO sc VALUES('S0009','C001');
INSERT INTO sc VALUES('S0009','C005');

常见面试题

前10条记录
select top 10 * form table1 where 范围
#select top 30 recid from A order by ricid(如果该字段不是自增长,就会出现问题)
查询从10到15的记录
select top 5 * from (select top 15 * from table order by id asc) table_别名 order by id desc
根据ip列查询重复的数据(根据单列判断重复)
SELECT * FROM proxy_ip
WHERE ip IN (SELECT ip FROM proxy_ip GROUP BY ip HAVING COUNT(ip) > 1)