inner join(join)
left join
right join
表设计
在我们初学阶段,往往都是随意建立一张表,表里面的描述千奇百怪,总想往里面塞东西。
但是有没有想过当我们想要分析一些信息的时候将会变得特别麻烦,比如说Student里面包含了Class的信息,当我们想要查看有什么班级的时候就需要对Class列进行分组或者去重的操作。
尤其是当学生数量变的特别多的时候,将会妨碍到我们拿出那短短的几行数据,于是我们就需要分析一张表的合理性,将独立共用的数据进行从表里面进行拆分。
首先建立一张Class表
字段名|主键|类型|占用字节数|长度|小数位数|允许空|默认值|字段说明|
----|----|----|----|----|----|----|----|----|----|----|----|----|
Id|v|uniqueidentifier|||||(newid())|主键|
Name||nvarchar||50||||名称|
建好后,我们耍点滑头把数据录进去
首先将Class的信息分组出来
select Class from Student group by Class
Class |
---|
一年级 |
七年级 |
三年级 |
九年级 |
二年级 |
八年级 |
六年级 |
四年级 |
然后将信息插入到Class表中
insert into Class
select newId() as Id,Class from Student
group by Class
这种做法的前提是双方的表结构一致才行,表结构一致的意思是数据类型要一致,不是列名一致
最后将我们的Student表中的Class的内容,更新为Class中的Id
update Student
set Student.Class=Class.Id
from Student
left join Class on Student.Class=Class.[Name]
再将我们Student表的Class的类型改为uniqueidentifier
可能在直接修改的过程中会出现这个错误
可以这么解决
把这个勾勾去掉即可
然后我们的Student的表结构成这样
P.S:为什么Class要改名为ClassId,这里没有提到的就是外键约束,在以前学校学习的时候会讲到两个表之间关联会通过主外键进行绑定,而当我们实际使用时却不这么干,是为什么?因为数据的变动成本较大,设置了主外键约束,就意味着主表的数据是不能随意删除,那当然如果是好的设计者,懂得视情况使用是最好了,但是往往懂的人少,所以大家都不这么玩,所以为了明白一眼看过去这是外键列,就通过表名+Id来表示这个是外键列,当然不守规矩的人有很多,得小心!
目前Class和Student的关系如下
P.S:关于列名的命名问题也是个很讲究的知识,你会发现我建表从不会StudentName,StudentId,StudentAge诸如此类的,为什么?
因为我的表就叫Student,所以Name叫StudentName这不是很奇怪吗,就连使用都会变成Student.StudentName,直接Student.Name不香吗?
联接
首先我们往Class表和Student插入一笔数据
insert into Class values(newId(),'测试')
insert into Student (Id) values(newId())
P.S:有的人喜欢用int做主键,有的人喜欢用GUID,各有各的好处,用GUID方便不同的数据库之间移植,而用int做主键占用空间小
inner join/join(内连接)
select s.* from Class as c
inner join Student as s on c.Id=s.ClassId
查询出来是否发现,不会出现Class为测试的学生和没有班级的学生,所以内连接的结果是有交集的数据,也可以理解为双方有关联的数据才会查询出来
P.S:内连接没有先后顺序
left join,right join(左连接,右连接)
select * from Class as c
left join Student as s on c.Id=s.ClassId
左连接的意思,是以左边为主体,查询数据,也就是说现在是以Class为主体数据,无论有没有匹配到都会将Class的所有数据显示出来
比如说Class有10条数据,而Student只有3条,那么没有匹配到的7条Class数据也会查询出来
右连接也同理,现在你会发现现在主体是Student
select * from Class as c
right join Student as s on c.Id=s.ClassId
不知道你有没有反应过来其实它们的意思是一样的
select * from Class as c
left join Student as s on c.Id=s.ClassId
-- 等同于
select * from Student as s
right join Class as c on c.Id=s.ClassId
看了这么多其实一般用left join就好了,没必要换来换去,然后视情况用inner join
题目
都要带上ClassName
--1、 查询结果显示为如下列(StudentId,SutdentName,ClassName),并且结果为双方有关联的数据
--2、 统计每个年级有多少人,查询结果显示为如下列(ClassName, Num),并且需要排序为降序
--3、 计算这批学生中男女各多少,从大到小进行排序
--4、 计算这批学生,男女的平均年龄是多少,并且要大于10
--5、 计算各地区的班级一共有多少人,并且人数大于1
--6、 计算各地区的平均年龄,并且查询出大于该平均年龄的学生,最后结果按按年龄升序(子查询)
--7、 计算各地区最小年龄,并且查询出该地区是最小年龄的学生信息,最后结果按按年龄降序(子查询)
--8、 计算Address为县的男女平均年龄,排序为降序
--9、 计算出生日期为1990到2005年之间的学生的最大年龄和最小年龄,可了解一下union 和 union all这两个的用法