多表关系
在实际项目开发的时候可能设计到多张表,表与表之间存在一定关系,如何设计表之间的关系让系统更加优化,需要考虑到多表之间关系。
1. 一对一(了解)
* 如:人和身份证
* 分析:一个人只有一个身份证,一个身份证只能对应一个人
2. 一对多(多对一)
* 如:部门和员工
* 分析:一个部门有多个员工,一个员工只能对应一个部门
3. 多对多
* 如:学生和课程
* 分析:一个学生可以选择很多门课程,一个课程也可以被很多学生选择
一对一关系
一个人有一个身份证号码,一个身份证号码只对应一个人
-- 创建身份证表
CREATE TABLE card(
id INT PRIMARY KEY,
number VARCHAR(18)
);
-- 设置身份证号码唯一
ALTER TABLE card MODIFY number VARCHAR(20) UNIQUE;
INSERT INTO card(id,number) VALUES(1,420923199211090512);
INSERT INTO card(id,number) VALUES(2,420923199310230807);
INSERT INTO card(id,number) VALUES(3,420923199007080908);
-- 创建人员表
CREATE TABLE person(
id INT PRIMARY KEY,
NAME VARCHAR(20),
cid INT
);
-- 给人员表添加外键
ALTER TABLE person ADD CONSTRAINT cid_kf FOREIGN KEY(cid) REFERENCES card(id);
-- 设置外键唯一
ALTER TABLE person MODIFY cid INT UNIQUE;
-- 向person表中添加数据
INSERT INTO person(id,NAME,cid) VALUES(1,"张三",1);
INSERT INTO person(id,NAME,cid) VALUES(2,"李四",2);
INSERT INTO person(id,NAME,cid) VALUES(3,"王五",3);
一对多关系
一个部门可以有多个员工,一个员工只能对应一个部门
-- 创建部门表(主表)
CREATE TABLE department(
id INT PRIMARY KEY,
NAME VARCHAR(20)
);
-- 向部门表中添加数据
INSERT INTO department(id,NAME) VALUES(1,"教研部");
INSERT INTO department(id,NAME) VALUES(2,"学工部");
INSERT INTO department(id,NAME) VALUES(3,"就业部");
SELECT * FROM department;
-- 创建员工表(从表)
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL,
age INT,
dep_id INT,
CONSTRAINT emp_depid_fk FOREIGN KEY(dep_id) REFERENCES department(id)
);
-- 向员工表中添加数据
INSERT INTO employee(NAME,age,dep_id) VALUES("张三",18,1);
INSERT INTO employee(NAME,age,dep_id) VALUES("李四",20,2);
INSERT INTO employee(NAME,age,dep_id) VALUES("王五",21,1);
INSERT INTO employee(NAME,age,dep_id) VALUES("赵六",19,3);
INSERT INTO employee(NAME,age,dep_id) VALUES("田七",24,2);
INSERT INTO employee(NAME,age,dep_id) VALUES("周八",23,3);
INSERT INTO employee(NAME,age,dep_id) VALUES("黄九",25,1);
SELECT * FROM employee;
多对多关系
一个学生可以选择很多门课程,一个课程也可以被很多学生选择
-- 创建学生表
CREATE TABLE student(
sid INT PRIMARY KEY,
NAME VARCHAR(20),
age INT
);
INSERT INTO student(sid,NAME,age) VALUES(1,"张三",20);
INSERT INTO student(sid,NAME,age) VALUES(2,"李四",19);
INSERT INTO student(sid,NAME,age) VALUES(3,"王五",18);
INSERT INTO student(sid,NAME,age) VALUES(4,"赵六",21);
INSERT INTO student(sid,NAME,age) VALUES(5,"田七",24);
INSERT INTO student(sid,NAME,age) VALUES(6,"周八",23);
-- 创建课程表
CREATE TABLE class(
cid INT PRIMARY KEY,
NAME VARCHAR(20)
);
INSERT INTO class(cid,NAME) VALUES(1,"Java基础");
INSERT INTO class(cid,NAME) VALUES(2,"HTML");
INSERT INTO class(cid,NAME) VALUES(3,"Javascript");
INSERT INTO class(cid,NAME) VALUES(4,"mysql");
-- 创建外键表
CREATE TABLE foreign_table(
sid INT,
cid INT,
CONSTRAINT sid_fk FOREIGN KEY(sid) REFERENCES student(sid), -- 外键sid 关联 student sid主键
CONSTRAINT cid_fk FOREIGN KEY(cid) REFERENCES class(cid) -- 外键cid 关联 class cid主键
);
INSERT INTO foreign_table(sid,cid) VALUES(1,1);
INSERT INTO foreign_table(sid,cid) VALUES(1,2);
INSERT INTO foreign_table(sid,cid) VALUES(1,3);
INSERT INTO foreign_table(sid,cid) VALUES(1,4);
INSERT INTO foreign_table(sid,cid) VALUES(2,1);
INSERT INTO foreign_table(sid,cid) VALUES(2,2);
INSERT INTO foreign_table(sid,cid) VALUES(3,4);
INSERT INTO foreign_table(sid,cid) VALUES(3,1);
多表查询
准备数据
-- 创建db4数据库
CREATE DATABASE db4;
-- 使用db4数据库
USE db4;
-- 创建user表
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT, -- 用户id
NAME VARCHAR(20), -- 用户姓名
age INT -- 用户年龄
);
-- 添加数据
INSERT INTO USER VALUES (1,'张三',23);
INSERT INTO USER VALUES (2,'李四',24);
INSERT INTO USER VALUES (3,'王五',25);
INSERT INTO USER VALUES (4,'赵六',26);
-- 订单表
CREATE TABLE orderlist(
id INT PRIMARY KEY AUTO_INCREMENT, -- 订单id
number VARCHAR(30), -- 订单编号
uid INT, -- 外键字段
CONSTRAINT ou_fk1 FOREIGN KEY (uid) REFERENCES USER(id)
);
-- 添加数据
INSERT INTO orderlist VALUES (1,'hm001',1);
INSERT INTO orderlist VALUES (2,'hm002',1);
INSERT INTO orderlist VALUES (3,'hm003',2);
INSERT INTO orderlist VALUES (4,'hm004',2);
INSERT INTO orderlist VALUES (5,'hm005',3);
INSERT INTO orderlist VALUES (6,'hm006',3);
INSERT INTO orderlist VALUES (7,'hm007',NULL);
-- 商品分类表
CREATE TABLE category(
id INT PRIMARY KEY AUTO_INCREMENT, -- 商品分类id
NAME VARCHAR(10) -- 商品分类名称
);
-- 添加数据
INSERT INTO category VALUES (1,'手机数码');
INSERT INTO category VALUES (2,'电脑办公');
INSERT INTO category VALUES (3,'烟酒茶糖');
INSERT INTO category VALUES (4,'鞋靴箱包');
-- 商品表
CREATE TABLE product(
id INT PRIMARY KEY AUTO_INCREMENT, -- 商品id
NAME VARCHAR(30), -- 商品名称
cid INT, -- 外键字段
CONSTRAINT cp_fk1 FOREIGN KEY (cid) REFERENCES category(id)
);
-- 添加数据
INSERT INTO product VALUES (1,'华为手机',1);
INSERT INTO product VALUES (2,'小米手机',1);
INSERT INTO product VALUES (3,'联想电脑',2);
INSERT INTO product VALUES (4,'苹果电脑',2);
INSERT INTO product VALUES (5,'中华香烟',3);
INSERT INTO product VALUES (6,'玉溪香烟',3);
INSERT INTO product VALUES (7,'计生用品',NULL);
-- 中间表
CREATE TABLE us_pro(
upid INT PRIMARY KEY AUTO_INCREMENT, -- 中间表id
uid INT, -- 外键字段。需要和用户表的主键产生关联
pid INT, -- 外键字段。需要和商品表的主键产生关联
CONSTRAINT up_fk1 FOREIGN KEY (uid) REFERENCES USER(id),
CONSTRAINT up_fk2 FOREIGN KEY (pid) REFERENCES product(id)
);
-- 添加数据
INSERT INTO us_pro VALUES (NULL,1,1);
INSERT INTO us_pro VALUES (NULL,1,2);
INSERT INTO us_pro VALUES (NULL,1,3);
INSERT INTO us_pro VALUES (NULL,1,4);
INSERT INTO us_pro VALUES (NULL,1,5);
INSERT INTO us_pro VALUES (NULL,1,6);
INSERT INTO us_pro VALUES (NULL,1,7);
INSERT INTO us_pro VALUES (NULL,2,1);
INSERT INTO us_pro VALUES (NULL,2,2);
INSERT INTO us_pro VALUES (NULL,2,3);
INSERT INTO us_pro VALUES (NULL,2,4);
INSERT INTO us_pro VALUES (NULL,2,5);
INSERT INTO us_pro VALUES (NULL,2,6);
INSERT INTO us_pro VALUES (NULL,2,7);
INSERT INTO us_pro VALUES (NULL,3,1);
INSERT INTO us_pro VALUES (NULL,3,2);
INSERT INTO us_pro VALUES (NULL,3,3);
INSERT INTO us_pro VALUES (NULL,3,4);
INSERT INTO us_pro VALUES (NULL,3,5);
INSERT INTO us_pro VALUES (NULL,3,6);
INSERT INTO us_pro VALUES (NULL,3,7);
INSERT INTO us_pro VALUES (NULL,4,1);
INSERT INTO us_pro VALUES (NULL,4,2);
INSERT INTO us_pro VALUES (NULL,4,3);
INSERT INTO us_pro VALUES (NULL,4,4);
INSERT INTO us_pro VALUES (NULL,4,5);
INSERT INTO us_pro VALUES (NULL,4,6);
INSERT INTO us_pro VALUES (NULL,4,7);
内连接查询
- 内连接查询语法
-- 显示内连接查询
SELECT 列名 FROM 表名1 [INNER] JOIN 表名2 ON 关联条件;
-- 隐式内连接查询
SELECT 列名 FROM 表名1,表名2 WHERE 关联条件;
- 内连接查询举例
-- 查询用户信息和对应的订单信息
-- 查询用户信息和对应的订单信息,起别名
-- 查询用户姓名,年龄。和订单编号
外连接查询
- 外连接查询语法
-- 左外连接查询
SELECT 列名 FROM 表名1 LEFT [OUTER] JOIN 表名2 ON 条件;
-- 右外连接查询
SELECT 列名 FROM 表名1 RIGHT [OUTER] JOIN 表名2 ON 条件;
- 外连接查询举例
-- 查询所有用户信息,以及用户对应的订单信息
SELECT
u.*,
o.number
FROM
USER u
LEFT OUTER JOIN
orderlist o
ON
o.uid=u.id;
-- 查询所有订单信息,以及订单所属的用户信息
SELECT
u.*,
o.number
FROM
USER u
RIGHT OUTER JOIN
orderlist o
ON
o.uid=u.id;
子查询
子查询就是利用SQL语句的查询结果,再结合其他SQL条件再次进行查询。
- 子查询的结果是一行一列
子查询的结果是一行一列,可以将子查询的结果当做某一个字段的值,作为where子句的条件;
-- 查询用户最大的年龄
SELECT MAX(age) FROM USER;
-- 查询年龄最大的用户姓名
select name ,age from user where age=(select max(age) from user);
- 子查询的结果是多行单列
子查询的结果是多行单列,可以将子查询的结果当做某一个字段的多个值,作为where子句的条件。
-- 查询张三和李四的id
select id from user where name in('张三','李四');
-- 查询张三和李四的订单信息
select * from orderlist where uid in (select id from user where name in('张三','李 四'));
- 子查询的结果是多行多列
子查询的结果是多行多列,可以将子查询的结果当做一个表来看待,并和其他表进行连接查询。
-- 查询订单表中id>4的订单信息
select * from orderlist where id>4;
-- 查询订单表中id大于4的订单信息和所属用户信息
select u.name,o.number from user u ,(select * from orderlist where id>4) o where o.uid=u.id;
自关联查询
- 准备数据
-- 创建员工表
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT, -- 员工编号
NAME VARCHAR(20), -- 员工姓名
mgr INT, -- 上级编号
salary DOUBLE -- 员工工资
);
-- 添加数据
INSERT INTO employee VALUES (1001,'孙悟空',1005,9000.00),
(1002,'猪八戒',1005,8000.00),
(1003,'沙和尚',1005,8500.00),
(1004,'小白龙',1005,7900.00),
(1005,'唐僧',NULL,15000.00),
(1006,'武松',1009,7600.00),
(1007,'李逵',1009,7400.00),
(1008,'林冲',1009,8100.00),
(1009,'宋江',NULL,16000.00);
-- 查询所有员工的姓名及其直接上级的姓名,没有上级的员工也需要查询
/*
分析
员工信息 employee表
条件:employee.mgr = employee.id
查询左表的全部数据,和左右两张表有交集部分数据,左外连接
*/
SELECT
e1.id,
e1.name,
e1.mgr,
e2.id,
e2.name
FROM
employee e1
LEFT OUTER JOIN
employee e2
ON
e1.mgr = e2.id;
多表查询练习
- 查询用户的编号、姓名、年龄。订单编号
/*
分析:
查询的表:用户表(user),订单表(orderlist)
查询的字段:用户编号,姓名,年龄,订单编号
查询的条件:user.id=orderlist.uid
*/
select
u.id,u.name,u.age,o.number
from
user u,orderlist o
where
u.id=o.uid;
- 查询所有的用户。用户的编号、姓名、年龄。订单编号
/*
分析:
查询的表:用户表(user),订单表(orderlist)。 所有用户,左外连接
查询的字段:用户编号,姓名,年龄,订单编号
查询的条件:orderlist.uid = user.id
*/
select
u.id,u.name,u.age,o.number
from
user u
left join
orderlist o
on
u.id=o.uid;
- 查询所有的订单。用户的编号、姓名、年龄。订单编号
/*
分析:
查询的表:用户表(user),订单表(orderlist)。所有订单,忧外连接
查询的字段:用户的编号、姓名、年龄、订单编号
查询的条件:orderlist.uid = user.id
*/
select
u.id,u.name,u.age,o.number
from
user u
right join
orderlist o
on
o.uid=u.id;
- 查询用户年龄大于23岁的信息。显示用户的编号、姓名、年龄。订单编号
/*
分析:
查询的表:用户表(user),订单表(orderlist)
查询的字段:用户的编号、姓名、年龄。订单编号
查询的条件:user.id=orderlist.uid and user.age>23
*/
select
u.id,u.name,u.age,o.number
from
user u,orderlist o
where
u.id=o.uid and u.age>23;
- 查询张三和李四用户的信息。显示用户的编号、姓名、年龄。订单编号
/*
分析:
查询的表:用户表(user),订单表(orderlist)
查询的字段:显示用户的编号、姓名、年龄。订单编号
查询的条件:user.name in ("张三","李四") and user.id=orderlist.uid;
*/
select
u.id,u.name,u.age,o.number
from
user u,
orderlist o
where
u.id=o.uid and u.name in ("张三","李四");
- 查询商品分类的编号、分类名称。分类下的商品名称
/*
分析:
查询的表:商品表(product)、分类表(category)
查询的字段:商品分类的编号、分类名称、商品名称
查询的条件:product.cid=category.id
*/
select
c.id,c.name,p.name
from
product p,
category c
where
p.cid=c.id;
- 查询所有的商品分类。商品分类的编号、分类名称。分类下的商品名称
/*
分析:
查询的表:商品表(product)、分类表(category)
查询的字段:商品分类的编号(id)、分类名称(name)、商品名称(name)
查询的条件:product.cid=category.id
*/
select
c.id,c.name,p.name
from
product p
right join
category c
on
p.cid=c.id;
- 查询所有的商品信息。商品分类的编号、分类名称。分类下的商品名称
/*
分析:
查询的表:商品表(product)、分类表(category)
查询的字段:商品分类的编号(id)、分类名称(name)、商品名称(name)
查询的条件:product.cid=category.id
*/
select
c.id,c.name,p.name
from
product p
left join
category c
on
p.cid=c.id;
- 查询所有的用户和该用户能查看的所有的商品。显示用户的编号、姓名、年龄。商品名称
/*
分析:
查询的表:用户表(user),商品表(product),中间表(us_pro)
查询的字段:用户的编号、姓名、年龄。商品名称
查询的条件:user.id=us_pro.uid and product.id=us_pro.pid;
*/
select
u.id,u.name,u.age,p.name
from
user u,
product p,
us_pro up
where
u.id=up.uid and p.id=up.pid;
- 查询张三和李四这两个用户可以看到的商品。显示用户的编号、姓名、年龄。商品名称
/*
分析:
查询的表:用户表(user),商品表(product),中间表(us_pro)
查询的字段:用户的编号、姓名、年龄。商品名称
查询的条件:
user.name in ("张三","李四")
and us_pro.uid=user.id;
and us_pro.pid=product.id;
*/
select
u.id,u.name,u.age,p.name
from
user u,product p,us_pro up
where
u.name in ("张三","李四") and up.uid=u.id and up.pid=p.id;