数据库-多表

一对多关系的建表原则:建立两张表

一张叫主表(一方)
一张叫从表(多方):从表(多方)中必须有个字段(列),引用主表(一方)的主键

外键:从表(多方)引用主表(一方)主键的那个字段(列)

多对多关系建表原则:需要创建第三张表

中间表中至少两个字段,这两个字段分别作为外键指向各自一方的主键.
数据库-多表_第1张图片




外键约束

语法:alter table 从表 add [constraint] 外键名称 foreign key (从表外键字段名) references 主表 (主表的主键);
[外键名称] 用于删除外键约束的,一般建议“_fk”结尾
alter table 从表 drop foreign key 外键名称




多表查询

1.交叉查询:查询到的数据是两个表相乘(主表(A,B,C),从表(a,b,c))=Aa,Ab,Ac…Ba,Bb,Bc…Ca,Cb,C*c,9条数据
2.内连接查询(使用的关键字 inner join – inner可以省略)
隐式内连接:select * from 主表,从表 where 主表.主键=从表.外键;
显示内连接:select * from A inner join B on 主表.主键=从表.外键;

3.外连接查询:
左外连接:select * from 主表 left outer join 从表 on 主表.主键=从表.外键----以左表为准,左表中的数据必须每条都有;
右外连接:select * from 主表 right outer join 从表 on 主表.主键=从表.外键;

多表查询小练习

#一对多
CREATE TABLE leimu(
	lid INT PRIMARY KEY AUTO_INCREMENT,
	lname VARCHAR(100)
);
CREATE TABLE shangpin(
	sid INT PRIMARY KEY AUTO_INCREMENT,
	sname VARCHAR(100),
	leimu_id INT,
	shangjia INT,
	##也可以把外键约束放从表里面,要注意标点符号
	CONSTRAINT id_leimu_fk FOREIGN KEY (leimu_id) REFERENCES leimu(lid)
);
ALTER TABLE shangpin ADD CONSTRAINT id_leimu_fk FOREIGN KEY (leimu_id) REFERENCES leimu(lid);

INSERT INTO leimu(lname) VALUES('服装');
INSERT INTO leimu(lname) VALUES('鞋子');
INSERT INTO leimu(lname) VALUES('手机');
INSERT INTO leimu(lname) VALUES('日化');
INSERT INTO leimu(lname) VALUES('汽车');

INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('奥迪',5,1);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('宝马',5,1);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('奔驰',5,0);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('沙宣',4,0);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('海飞丝',4,0);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('潘婷',4,1);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('小米',3,0);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('华为',3,1);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('耐克',2,1);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('阿迪',2,0);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('杰克琼斯',1,0);
INSERT INTO shangpin(sname,leimu_id,shangjia) VALUES('优衣库',1,1);

1.
    #查看哪些商品上架了
    SELECT *FROM shangpin WHERE shangjia=1;
    #查看什么类目的商品上架了
    #第一步先创建连接
    ALTER TABLE shangpin ADD CONSTRAINT shangpin_fk FOREIGN KEY (leimu_id) REFERENCES leimu(lid);
    #第二步内连接查询有商品上架的类目(显示全部字段(列))
    SELECT * FROM leimu,shangpin WHERE shangpin.leimu_id=leimu.lid AND shangjia>0;
    #第三步内连接查询有商品上架的类目(只显示lname字段(列))
    SELECT lname FROM leimu,shangpin WHERE shangpin.leimu_id=leimu.lid AND shangjia>0;
    #第三步内连接查询有商品上架的类目(去重)
    SELECT DISTINCT lname  FROM leimu,shangpin WHERE shangpin.leimu_id=leimu.lid AND shangjia>0;
    #主表,从表可以简写
    SELECT DISTINCT lname  FROM leimu l,shangpin sp WHERE sp.leimu_id=l.lid AND shangjia>0;

2.
	#查询各个分类的商品个数
	内连接查询
	SELECT lname,COUNT(*) FROM leimu,shangpin WHERE leimu.lid=shangpin.leimu_id GROUP BY leimu_id;
	外连接查询
	SELECT lname,COUNT(leimu_id) FROM leimu l LEFT OUTER JOIN shangpin sp ON l.lid = sp.leimu_id GROUP BY lname;

子查询

一个查询的结果,作为另外一个查询的一部分

上面例子   
#查汽车的详情 
SELECT * FROM shangpin WHERE leimu_id=(SELECT lid FROM leimu WHERE lname='汽车');
#查汽车和手机的详情 
SELECT * FROM shangpin sp WHERE sp.leimu_id IN( SELECT l.lid FROM leimu l WHERE l.lname IN('汽车','手机'));

小练习

CREATE TABLE people(
	empno INT PRIMARY KEY AUTO_INCREMENT,#工号
	pname		VARCHAR(50),
	job		VARCHAR(50),
	mgr		INT,#管理者编号
	hiredate	DATE,#入职时间
	sal		DECIMAL(7,2),#工资
	comm		DECIMAL(7,2),#奖金
	deptno		INT#部门编号
	
);

INSERT INTO people VALUES(7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20);
INSERT INTO people VALUES(7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600,300,30);
INSERT INTO people VALUES(7521,'WARD','SALESMAN',7698,'1981-02-22',1250,500,30);
INSERT INTO people VALUES(7566,'JONES','MANAGER',7839,'1981-04-02',2975,NULL,20);
INSERT INTO people VALUES(7654,'MARTIN','SALESMAN',7698,'1981-09-28',1250,1400,30);
INSERT INTO people VALUES(7698,'BLAKE','MANAGER',7839,'1981-05-01',2850,NULL,30);
INSERT INTO people VALUES(7782,'CLARK','MANAGER',7839,'1981-06-09',2450,NULL,10);
INSERT INTO people VALUES(7788,'SCOTT','ANALYST',7566,'1987-04-19',3000,NULL,20);
INSERT INTO people VALUES(7839,'KING','PRESIDENT',NULL,'1981-11-17',5000,NULL,10);
INSERT INTO people VALUES(7844,'TURNER','SALESMAN',7698,'1981-09-08',1500,0,30);
INSERT INTO people VALUES(7876,'ADAMS','CLERK',7788,'1987-05-23',1100,NULL,20);
INSERT INTO people VALUES(7900,'JAMES','CLERK',7698,'1981-12-03',950,NULL,30);
INSERT INTO people VALUES(7902,'FORD','ANALYST',7566,'1981-12-03',3000,NULL,20);
INSERT INTO people VALUES(7934,'MILLER','CLERK',7782,'1982-01-23',1300,NULL,10);

CREATE TABLE dept(
	deptno		INT,
	dname		VARCHAR(14),
	loc		VARCHAR(13)
);
INSERT INTO dept VALUES(10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO dept VALUES(20, 'RESEARCH', 'DALLAS');
INSERT INTO dept VALUES(30, 'SALES', 'CHICAGO');
INSERT INTO dept VALUES(40, 'OPERATIONS', 'BOSTON');

#单表练习
-- 1.  	查询工资大于1200的员工姓名和工资
SELECT pname,sal FROM people WHERE sal>=1200;
-- 2.	查询员工号为7654的员工的姓名和部门号
SELECT pname,deptno FROM people WHERE empno=7654;
-- 3.	选择工资不在1000到2000的员工的姓名和工资
SELECT pname,sal FROM people WHERE sal>2000 OR sal<1000;
-- 4.	选择雇用时间在1981-05-01到1981-10-01之间的员工姓名,job和雇用时间
SELECT pname,job,hiredate FROM people WHERE hiredate >'1981-05-01' AND hiredate <'1981-10-01';
SELECT pname,job,hiredate FROM people WHERE hiredate BETWEEN '1981-05-01' AND '1981-10-01';
-- 5.	选择在20或10号部门工作的员工姓名和部门号
SELECT pname,deptno FROM people WHERE deptno IN (10,20);
-- 6.	选择在1981年雇用的员工的姓名和雇用时间
SELECT pname,hiredate FROM people WHERE hiredate BETWEEN '1981-01-01' AND '1981-12-31'
SELECT pname,hiredate FROM people WHERE hiredate LIKE '1981%';
-- 7.	选择公司中没有管理者的员工姓名及job
SELECT pname,job FROM people WHERE mgr IS NULL;
-- 8.	选择公司中有奖金的员工姓名,工资和奖金
SELECT pname,sal,comm FROM people WHERE comm IS NOT NULL ;
-- 9.	选择员工姓名的第三个字母是a的员工姓名
SELECT pname FROM people WHERE pname LIKE '__a%';
-- 10.	选择姓名中有字母a和e的员工姓名(%代表0个或者多个字符)
SELECT pname FROM people WHERE pname LIKE '%a%e%' OR pname LIKE '%e%a%';
SELECT ename FROM emp WHERE ename LIKE '%a%' AND  ename LIKE '%e%';
-- 12.	查询员工号,姓名,工资,以及工资提高百分之20%后的结果(请使用别名new salary)
SELECT empno,pname,sal,sal*1.2 `new salary` FROM people;
-- 13.	将员工的姓名按首字母排序,并写出姓名的长度(length)
SELECT pname,LENGTH(pname) FROM people  ORDER BY pname;
-- 14.	查询公司员工工资的最大值,最小值,平均值,总和
SELECT SUM(sal),MAX(sal),MIN(sal),AVG(sal) FROM people;
-- 15.	查询各job的员工工资的最大值,最小值,平均值,总和
SELECT job,SUM(sal),MAX(sal),MIN(sal),AVG(sal) FROM people GROUP BY job ;
-- 16.	查询具体各个job的员工人数
SELECT job,COUNT(pname) FROM people GROUP BY job ;
-- 17.	查询员工最高工资和最低工资的差距(请用别名 DIFFERENCE)
SELECT MAX(sal)-MIN(sal) DIFFERENCE FROM people;
-- 18.	查询各个管理者手下员工的最低工资,其中最低工资不能低于1000,没有管理者的员工不计算在内
SELECT mgr,MIN(sal) FROM people GROUP BY mgr HAVING mgr IS NOT NULL AND MIN(sal)>1000;
-- 19.	查询所有部门的名字,loc,员工数量和工资平均值
SELECT dname,loc,COUNT(people.pname),AVG(people.sal) FROM dept,people WHERE dept.deptno=people.deptno GROUP BY dept.dname;
-- 1、按员工编号升序排列不在10号部门工作的员工信息
SELECT *FROM people WHERE deptno<>10 ORDER BY empno;
-- 2、查询姓名第二个字母不是”A”且薪水大于800元的员工信息,按年薪降序排列
SELECT *,sal*12 nianxin FROM people WHERE NOT pname  LIKE "_A%" AND sal>800 ORDER BY nianxin DESC ;
-- 3、求每个部门的平均薪水
SELECT deptno,AVG(sal) FROM people GROUP BY deptno;
-- 4、求各个部门的最高薪水
SELECT deptno,MAX(sal) FROM people GROUP BY deptno;
-- 5、求每个部门每个岗位的最高薪水
SELECT deptno,job, MAX(sal) FROM people GROUP BY deptno,job;
-- 6、求平均薪水大于2000的部门编号
SELECT deptno FROM people GROUP BY deptno HAVING AVG(sal)>2000;
-- 8、求最高薪水的员工信息
SELECT *FROM people WHERE sal=(SELECT MAX(sal) FROM people) ;
-- 9、求多于平均薪水的员工信息
SELECT *FROM people WHERE sal>(SELECT AVG(sal) FROM people);
-- 11、求各个部门薪水最高的员工信息
SELECT *FROM people WHERE sal IN (SELECT MAX(sal) FROM people GROUP BY deptno);
SELECT * FROM people,(SELECT deptno, MAX(sal) maxsal FROM people GROUP BY deptno) d WHERE people.deptno = d.deptno AND people.sal = d.maxsal;
-- 1.  查询和SCOTT相同部门的员工姓名和雇用日期
SELECT pname,hiredate FROM people WHERE deptno=(SELECT deptno FROM people WHERE pname='SCOTT');
-- 2.	查询工资比公司平均工资高的员工的员工号,姓名和工资。
SELECT empno,pname,sal FROM people WHERE sal>(SELECT AVG(sal) FROM people);
-- 3.(难度较高,可删除)查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资
#翻译一下
#  列出员工号,姓名,工资,从people表,	(部门平均工资表)自定义名称d			   条件是 people表的部门编号=d表的部门编号 且people表的工资>d表的平均工资
SELECT empno,pname,sal FROM people,(SELECT deptno,AVG(sal) avgsal FROM people GROUP BY deptno) d WHERE people.deptno = d.deptno AND people.sal > d.avgsal;
-- 4.	查询和姓名中包含字母u的员工在相同部门的员工的员工号和姓名(可以用=也可以用IN)
SELECT empno,pname,deptno FROM people WHERE deptno=(SELECT deptno FROM people WHERE pname LIKE '%u%');
-- 6. 查询管理者是KING的员工姓名和工资 
SELECT pname,sal FROM people WHERE mgr IN (SELECT empno FROM people WHERE pname='KING');

你可能感兴趣的:(数据库-多表)