--创建emp表主键自增CREATETABLEemp(eidINTPRIMARYKEYAUTO_INCREMENT,enameVARCHAR(20),ageINT,dep_nameVARCHAR(20),dep_locationVARCHAR(20));--添加数据INSERTINTOemp(ename,age,dep_name,dep_location)VALUES('张百万',20,'研发部','广州');INSERTINTOemp(ename,age,dep_name,dep_location)VALUES('赵四',21,'研发部','广州');INSERTINTOemp(ename,age,dep_name,dep_location)VALUES('广坤',20,'研发部','广州');INSERTINTOemp(ename,age,dep_name,dep_location)VALUES('小斌',20,'销售部','深圳');INSERTINTOemp(ename,age,dep_name,dep_location)VALUES('艳秋',22,'销售部','深圳');INSERTINTOemp(ename,age,dep_name,dep_location)VALUES('大玲子',18,'销售部','深圳');1.2.2单表的问题1)冗余,同一个字段中出现大量的重复数据
1.多表方式设计department部门表:id,dep_name,dep_locationemployee员工表:eid,ename,age,dep_id2.删除emp表,重新创建两张表
--创建部门表--一方,主表CREATETABLEdepartment(idINTPRIMARYKEYAUTO_INCREMENT,dep_nameVARCHAR(30),dep_locationVARCHAR(30));--创建员工表--多方,从表CREATETABLEemployee(eidINTPRIMARYKEYAUTO_INCREMENT,enameVARCHAR(20),ageINT,dept_idINT);3.添加部门表数据
--添加2个部门INSERTINTOdepartmentVALUES(NULL,'研发部','广州'),(NULL,'销售部','深圳');SELECT*FROMdepartment;4.添加员工表数据
--添加员工,dep_id表示员工所在的部门INSERTINTOemployee(ename,age,dept_id)VALUES('张百万',20,1);INSERTINTOemployee(ename,age,dept_id)VALUES('赵四',21,1);INSERTINTOemployee(ename,age,dept_id)VALUES('广坤',20,1);INSERTINTOemployee(ename,age,dept_id)VALUES('小斌',20,2);INSERTINTOemployee(ename,age,dept_id)VALUES('艳秋',22,2);INSERTINTOemployee(ename,age,dept_id)VALUES('大玲子',18,2);SELECT*FROMemployee;1.3.2表关系分析1)员工表中有一个字段dept_id与部门表中的主键对应,员工表的这个字段就叫做外键2)拥有外键的员工表被称为从表,与外键对应的主键所在的表叫做主表
解决方案:
语法格式:1.新建表时添加外键
[CONSTRAINT][外键约束名称]FOREIGNKEY(外键字段名)REFERENCES主表名(主键字段名)1.已有表添加外键
ALTERTABLE从表ADD[CONSTRAINT][外键约束名称]FOREIGNKEY(外键字段名)REFERENCES主表(主键字段名);1)重新创建employee表,添加外键约束
--先删除employee表DROPTABLEemployee;--重新创建employee表,添加外键约束CREATETABLEemployee(eidINTPRIMARYKEYAUTO_INCREMENT,enameVARCHAR(20),ageINT,dept_idINT,--添加外键约束CONSTRAINTemp_dept_fkFOREIGNKEY(dept_id)REFERENCESdepartment(id));2)插入数据
--正常添加数据(从表外键对应主表主键)INSERTINTOemployee(ename,age,dept_id)VALUES('张百万',20,1);INSERTINTOemployee(ename,age,dept_id)VALUES('赵四',21,1);INSERTINTOemployee(ename,age,dept_id)VALUES('广坤',20,1);INSERTINTOemployee(ename,age,dept_id)VALUES('小斌',20,2);INSERTINTOemployee(ename,age,dept_id)VALUES('艳秋',22,2);INSERTINTOemployee(ename,age,dept_id)VALUES('大玲子',18,2);--插入一条有问题的数据(部门id不存在)--Cannotaddorupdateachildrow:aforeignkeyconstraintfailsINSERTINTOemployee(ename,age,dept_id)VALUES('错误',18,3);1.4.3删除外键约束语法格式
altertable从表dropforeignkey外键约束名称1)删除外键约束
--删除employee表中的外键约束,外键约束名emp_dept_fkALTERTABLEemployeeDROPFOREIGNKEYemp_dept_fk;2)再将外键添加回来
语法格式
ALTERTABLE从表ADD[CONSTRAINT][外键约束名称]FOREIGNKEY(外键字段名)REFERENCES主表(主键字段名);--可以省略外键名称,系统会自动生成一个ALTERTABLEemployeeADDFOREIGNKEY(dept_id)REFERENCESdepartment(id);1.4.4外键约束的注意事项1)从表外键类型必须与主表主键类型一致否则创建失败.
2)添加数据时,应该先添加主表中的数据.
--添加一个新的部门INSERTINTOdepartment(dep_name,dep_location)VALUES('市场部','北京');--添加一个属于市场部的员工INSERTINTOemployee(ename,age,dept_id)VALUES('老胡',24,3);3)删除数据时,应该先删除从表中的数据.
--删除数据时应该先删除从表中的数据--报错Cannotdeleteorupdateaparentrow:aforeignkeyconstraintfails--报错原因不能删除主表的这条数据,因为在从表中有对这条数据的引用DELETEFROMdepartmentWHEREid=3;--先删除从表的关联数据DELETEFROMemployeeWHEREdept_id=3;--再删除主表的数据DELETEFROMdepartmentWHEREid=3;1.4.5级联删除操作(了解)1)删除employee表,重新创建,添加级联删除
--重新创建添加级联操作CREATETABLEemployee(eidINTPRIMARYKEYAUTO_INCREMENT,enameVARCHAR(20),ageINT,dept_idINT,CONSTRAINTemp_dept_fkFOREIGNKEY(dept_id)REFERENCESdepartment(id)--添加级联删除ONDELETECASCADE);--添加数据INSERTINTOemployee(ename,age,dept_id)VALUES('张百万',20,1);INSERTINTOemployee(ename,age,dept_id)VALUES('赵四',21,1);INSERTINTOemployee(ename,age,dept_id)VALUES('广坤',20,1);INSERTINTOemployee(ename,age,dept_id)VALUES('小斌',20,2);INSERTINTOemployee(ename,age,dept_id)VALUES('艳秋',22,2);INSERTINTOemployee(ename,age,dept_id)VALUES('大玲子',18,2);--删除部门编号为2的记录DELETEFROMdepartmentWHEREid=2;2.多表关系设计实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系,接下来我们一起学习一下多表关系设计方面的知识
1)分析:省和市之间的关系是一对多关系,一个省包含多个市
2)SQL是实现
#创建省表(主表,注意:一定要添加主键约束)CREATETABLEprovince(idINTPRIMARYKEYAUTO_INCREMENT,NAMEVARCHAR(20),descriptionVARCHAR(20));#创建市表(从表,注意:外键类型一定要与主表主键一致)CREATETABLEcity(idINTPRIMARYKEYAUTO_INCREMENT,NAMEVARCHAR(20),descriptionVARCHAR(20),pidINT,--添加外键约束CONSTRAINTpro_city_fkFOREIGNKEY(pid)REFERENCESprovince(id));3)查看表关系
2)SQL实现
#创建演员表CREATETABLEactor(idINTPRIMARYKEYAUTO_INCREMENT,NAMEVARCHAR(20));#创建角色表CREATETABLErole(idINTPRIMARYKEYAUTO_INCREMENT,NAMEVARCHAR(20));#创建中间表CREATETABLEactor_role(--中间表自己的主键idINTPRIMARYKEYAUTO_INCREMENT,--指向actor表的外键aidINT,--指向role表的外键ridINT);3)添加外键约束
--为中间表的aid字段,添加外键约束指向演员表的主键ALTERTABLEactor_roleADDFOREIGNKEY(aid)REFERENCESactor(id);--为中间表的rid字段,添加外键约束指向角色表的主键ALTERTABLEactor_roleADDFOREIGNKEY(rid)REFERENCESrole(id);4)查看表关系
1)创建db3_2数据库
--创建db3_2数据库,指定编码CREATEDATABASEdb3_2CHARACTERSETutf8;2)创建分类表与商品表
3)插入数据
1)语法格式
SELECT字段名FROM表1,表2;2)使用交叉连接查询商品表与分类表
SELECT*FROMcategory,products;3)观察查询结果,产生了笛卡尔积(得到的结果是无法使用的)
2)笛卡尔积
假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}。
from子句后面直接写多个表名使用where指定连接条件的这种连接方式是隐式内连接.使用where条件过滤无用的数据
SELECT字段名FROM左表,右表WHERE连接条件;1)查询所有商品信息和对应的分类信息
2)查询商品表的商品名称和价格,以及商品的分类信息可以通过给表起别名的方式,方便我们的查询(有提示)
SELECTp.`pname`,p.`price`,c.`cname`FROMproductsp,categorycWHEREp.`category_id`=c.`cid`;3)查询格力空调是属于哪一分类下的商品
使用innerjoin...on这种方式,就是显式内连接语法格式
SELECT字段名FROM左表[INNER]JOIN右表ON条件--inner可以省略1)查询所有商品信息和对应的分类信息
#显式内连接查询SELECT*FROMproductspINNERJOINcategorycONp.category_id=c.cid;2)查询鞋服分类下,价格大于500的商品名称和价格
#查询鞋服分类下,价格大于500的商品名称和价格--我们需要确定的几件事--1.查询几张表products&category--2.表的连接条件从表.外键=主表的主键--3.查询的条件cname='鞋服'andprice>500--4.要查询的字段pnamepriceSELECTp.pname,p.priceFROMproductspINNERJOINcategorycONp.category_id=c.cidWHEREp.price>500ANDcname='鞋服';3.4.2外连接查询3.4.2.1左外连接1)语法格式
2)左外连接,查询每个分类下的商品个数
SELECT查询字段FROM表WHERE字段=(子查询);1.通过子查询的方式,查询价格最高的商品信息
#通过子查询的方式,查询价格最高的商品信息--1.先查询出最高价格SELECTMAX(price)FROMproducts;--2.将最高价格作为条件,获取商品信息SELECT*FROMproductsWHEREprice=(SELECTMAX(price)FROMproducts);2.查询化妆品分类下的商品名称商品价格
#查询化妆品分类下的商品名称商品价格--先查出化妆品分类的idSELECTcidFROMcategoryWHEREcname='化妆品';--根据分类id,去商品表中查询对应的商品信息SELECTp.`pname`,p.`price`FROMproductspWHEREp.`category_id`=(SELECTcidFROMcategoryWHEREcname='化妆品');3.查询小于平均价格的商品信息
--1.查询平均价格SELECTAVG(price)FROMproducts;--1866--2.查询小于平均价格的商品SELECT*FROMproductsWHEREprice<(SELECTAVG(price)FROMproducts);4.3子查询的结果作为一张表语法格式
SELECT查询字段FROM(子查询)表别名WHERE条件;1.查询商品中,价格大于500的商品信息,包括商品名称商品价格商品所属分类名称
--1.先查询分类表的数据SELECT*FROMcategory;--2.将上面的查询语句作为一张表使用SELECTp.`pname`,p.`price`,c.cnameFROMproductsp--子查询作为一张表使用时要起别名才能访问表中字段INNERJOIN(SELECT*FROMcategory)cONp.`category_id`=c.cidWHEREp.`price`>500;注意:当子查询作为一张表的时候,需要起别名,否则无法访问表中的字段。
SELECT查询字段FROM表WHERE字段IN(子查询);1.查询价格小于两千的商品,来自于哪些分类(名称)
1.查询家电类与鞋服类下面的全部商品信息
#查询家电类与鞋服类下面的全部商品信息--先查询出家电与鞋服类的分类IDSELECTcidFROMcategoryWHEREcnameIN('家电','鞋服');--根据cid查询分类下的商品信息SELECT*FROMproductsWHEREcategory_idIN(SELECTcidFROMcategoryWHEREcnameIN('家电','鞋服'));
1.子查询如果查出的是一个字段(单列),那就在where后面作为条件使用.2.子查询如果查询出的是多个字段(多列),就当做一张表使用(要起别名).
1,尽量遵循范式理论的规约,尽可能少的冗余字段,让数据库设计看起来精致、优雅、让人心醉。2,合理的加入冗余字段这个润滑剂,减少join,让数据库执行性能更高更快。