数据库学习第四天之多表查询

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33621967/article/details/53019622

表与表之间的关系包含以下几种:
1)1对1(示例:一夫一妻)
2)1对多,多对1(一个人可以拥有多辆汽车,要求查询出某人所拥有的所有汽车。)
3)多对多(一个人可以拥有多种角色,如某人,即是父亲、又是儿子、又是丈夫。而同时这三个角色又可以给其他所有的人。

使用关联查询和子查询:
当一个表的数据不能满足我们的需要时,我们就要从多个表中查询数据。此时必须使用关联查询:
inner join – 内关联,双方必须都要存在。
left join -左关联。以左边数据为准。
right join - 右关联。

SHOW VARIABLES LIKE 'character%';

//多表关系----第一种:一对一关系!
//躲表建立1对1关系----注意保证外键字段唯一!
//创建男人表
CREATE TABLE man(
    id VARCHAR(32) PRIMARY KEY,
    NAME VARCHAR(30)
);
//创建女人表---失败品
CREATE TABLE woman(
    id VARCHAR(32) PRIMARY KEY,
    NAME VARCHAR(30),
    husband VARCHAR(32),
    CONSTRAINT wm_fk FOREIGN KEY(husband) REFERENCES man(id)
);
//上面这个表创建出来是1对多的关系,但是由于外键那不是唯一的
DROP TABLE woman;
CREATE TABLE woman(
    id VARCHAR(32) PRIMARY KEY,
    NAME VARCHAR(30),
    husband VARCHAR(32) UNIQUE,
    CONSTRAINT wm_fk FOREIGN KEY(husband) REFERENCES man(id)
);

//往表中插入行数据
INSERT INTO man VALUES('1','张三');
INSERT INTO man VALUES('2','李四');
INSERT INTO man VALUES('3','王五');
INSERT INTO man VALUES('4','王大发');

//往woman表中插入行数据
INSERT INTO woman VALUES('1','小花','1');
INSERT INTO woman VALUES('2','玉芬','2');
INSERT INTO woman VALUES('3','王大嫂','4');

//查询出所有的夫妻关系
//第一种插询方式
SELECT man.name 丈夫,woman.NAME 妻子 FROM man INNER JOIN woman ON man.id=woman.husband;
//第二种查询方式
SELECT m.name AS 丈夫,w.name AS 妻子 FROM man AS m INNER JOIN woman AS w ON m.id=w.husband;

//查询出光棍
SELECT man.name FROM man LEFT JOIN woman ON woman.husband IS NULL;
SELECT man.name AS 光棍 FROM man LEFT JOIN woman ON woman.husband=man.id WHERE woman.id IS NULL;
//由于外键是相对于主表中的主键而言,所以外键的值必须包含在主表的主键值范围内!所以woman表中的所有女人必须对应一个丈夫!没有寡妇
------------------
二、1对多
※第三范式: 1方建主表(id为主键字段), 多方建外键字段(pid--参考主表的主键id,不加UNIQUE)
//创建人表
CREATE TABLE person(
    id VARCHAR(32) PRIMARY KEY,
    NAME VARCHAR(30),
    sex CHAR(1) DEFAULT '0'
);

//创建汽车表
CREATE TABLE car(
    id VARCHAR(32) PRIMARY KEY,
    NAME VARCHAR(30),
    price NUMERIC(6,2),
    pid VARCHAR(32),
    CONSTRAINT car_fk FOREIGN KEY(pid) REFERENCES person(id)
);

//往两个表中插入相关的行数据
INSERT INTO person VALUES('1','Jack','0');
INSERT INTO person VALUES('2','张三','0');
INSERT INTO person VALUES('3','Rose玫瑰','1');
INSERT INTO person VALUES('4','机械先驱','0');
INSERT INTO person VALUES('5','克洛克达尔','1');

INSERT INTO car VALUES('C001','宝马A系',40.5,'1');
INSERT INTO car VALUES('C002','BenZB系',56.6,'1');
INSERT INTO car VALUES('C003','QQ',4.54,'1');
INSERT INTO car VALUES('C004','Audi',5.56,'2');
INSERT INTO car VALUES('C005','Horse',85.2,'4');
INSERT INTO car VALUES('C007','广汽一众',3.65,'4');
//外键字段可以为NULL
INSERT INTO car(id,NAME,price) VALUES('C006','fentian',22.0);

//◇查询哪些人有哪些车
SELECT * FROM person INNER JOIN car ON person.id=car.pid;
SELECT person.name,car.name,car.price FROM person INNER JOIN car ON person.id=car.pid;

//◇查询Jack有哪些车
SELECT person.name,car.name,car.price FROM person INNER JOIN car ON person.id=car.pid WHERE person.name='jack';

//◇查询哪些人有两辆或两辆以上的车
//根据题目的意思我并不觉得这是失败品!
SELECT person.name FROM person INNER JOIN car ON person.id=car.pid GROUP BY car.pid HAVING COUNT(car.pid)>=2;
//第二种理解意思(连人带车都给列举出来,上面那种是不行的!)
SELECT person.name,car.name,car.price FROM person INNER JOIN car ON person.id=car.pid WHERE person.id IN('1','4') ;
//将上面的id字段写活!
SELECT person.id FROM person INNER JOIN car ON person.id=car.pid GROUP BY car.pid HAVING COUNT(car.pid)>=2;
//将上面两步合起来即可达到演示效果!
SELECT car.name,car.price,person.name FROM person INNER JOIN car ON person.id=car.pid WHERE person.id
    IN (SELECT person.id FROM person INNER JOIN car ON person.id=car.pid GROUP BY car.pid HAVING COUNT(car.pid)>=2);

//精简做法
SELECT car.name,car.price,person.name FROM car INNER JOIN person ON person.id=car.pid WHERE person.id
    IN (SELECT pid FROM car GROUP BY pid HAVING COUNT(pid)>=2) ORDER BY person.name DESC;
============
//综上所述!一定要时时刻刻想到IN(子查询)---很关键!内连接也很关键!
============

//◇查询哪些人没有车(左连接)
SELECT person.name 姓名,(CASE sex WHEN '0' THEN '男' WHEN '1' THEN '女' ELSE '其他' END) 性别
    FROM person LEFT JOIN car ON person.id=car.pid WHERE car.id IS NULL;

//试着删除汽车编号为C001的汽车(删除成功)
DELETE FROM car WHERE id='C001';
//试着删除编号为1的jack车主(删除失败!因为两个表之间有关联!person表中关联了car表中的数据,所有删除时要格外小心!)
DELETE FROM person WHERE id='1';
-------------------------------
//3.演示多对多的关系!
三、多对多( 3个表= 2个实体表 + 1个关系表 )
※第三范式: 两个实体都建成独立的主表, 另外再单独建一个关系表(采用联合主键)
1、分别建议两个实体表(没有外键,但有自己的主键, 没有冗余信息)
CREATE TABLE stud(
    id VARCHAR(32) PRIMARY KEY,
    NAME VARCHAR(30)
);
CREATE TABLE ject(
    id VARCHAR(32) PRIMARY KEY,
    NAME VARCHAR(30)
);
//再建一个独立的表!(注意建表时不指定外键!建完表之后再指定!)
CREATE TABLE sj(
    studid VARCHAR(32) NOT NULL,
    jectid VARCHAR(32)
);
//在指定外键的时候注意一个易错的小细节!先建联合主键再建外键!
//下面演示是错的!
ALTER TABLE sj ADD CONSTRAINT sj_fk1 FOREIGN KEY(studid) REFERENCES stud(id);
ALTER TABLE sj ADD CONSTRAINT sj_fk2 FOREIGN KEY(jectid) REFERENCES ject(id);
ALTER TABLE sj ADD CONSTRAINT sj_pk PRIMARY KEY(studid,jectid);
//下面是正确的演示
ALTER TABLE sj DROP FOREIGN KEY sj_fk1;
ALTER TABLE sj DROP FOREIGN KEY sj_fk2;
ALTER TABLE sj ADD CONSTRAINT sj_pk PRIMARY KEY(studid,jectid);
ALTER TABLE sj ADD CONSTRAINT sj_fk1 FOREIGN KEY(studid) REFERENCES stud(id);
ALTER TABLE sj ADD CONSTRAINT sj_fk2 FOREIGN KEY(jectid) REFERENCES ject(id);

3、添加一些演示数据
//实体表1
INSERT INTO stud VALUES('S001','Jack');
INSERT INTO stud VALUES('S002','Rose');
INSERT INTO stud VALUES('S003','Tom');
INSERT INTO stud VALUES('S004','张三');
//实体表2
INSERT INTO ject VALUES('J001','Java');
INSERT INTO ject VALUES('J002','Oracle');
INSERT INTO ject VALUES('J003','XML');
INSERT INTO ject VALUES('J004','JSP');
INSERT INTO ject VALUES('J005','Game');

//关系表
INSERT INTO sj VALUES('S001','J001');
INSERT INTO sj VALUES('S001','J003');
INSERT INTO sj VALUES('S001','J004');
INSERT INTO sj VALUES('S002','J002');
INSERT INTO sj VALUES('S002','J003');
INSERT INTO sj VALUES('S002','J004');

//查询哪些人选了哪些课
//SQL组织的1992标准,可用,但效率不高
SELECT stud.name 学生,ject.name 课程 FROM stud,sj,ject WHERE stud.id=sj.studid AND sj.jectid=ject.id;

//SQL组织的1996标准,效率高,推荐使用---关联
SELECT stud.name 学生,ject.name 课程 FROM stud INNER JOIN sj ON stud.id=sj.studid INNER JOIN ject ON ject.id=sj.jectid;

//查询哪些人没选课(左,又连接)
SELECT stud.name FROM stud LEFT JOIN sj ON stud.id=sj.studid LEFT JOIN ject ON sj.jectid=ject.id WHERE ject.id IS NULL;

//查询哪些课没人选
SELECT ject.name 课程 FROM stud RIGHT JOIN sj ON sj.studid=stud.id RIGHT JOIN ject ON ject.id=sj.jectid WHERE stud.id IS NULL;
//第二种查法
SELECT ject.name 课程 FROM ject LEFT JOIN sj ON sj.jectid=ject.id LEFT JOIN stud ON stud.id=sj.studid WHERE stud.id IS NULL;

猜你喜欢

转载自blog.csdn.net/qq_33621967/article/details/53019622