上一篇博文说到相关子查询效率低下,那我们怎么能将不同表的信息一起查询出来呢?这就需要用到表联接。

和之前的UNION组合查询不同,UNION是将不同的表组合起来,也就是纵向联接,说白了就是竖着拼起来。

而表联接是通过笛卡尔乘积将表进行横向联接,所谓的通过笛卡尔乘积简单说就是两表的行依次相联再相加。要想更详细的理解可以百度下,毕竟本文主要是汇总SQL语句。

现在有如下两张表:

这是当初老师布置的一份作业,我偷个懒就不改数据了。不过把这些真神级人物的大名贴出来做“实验”总觉得心里有很虚,更何况大部分都是IT业的。如有什么不敬我先道个歉,别跟我一般见识。

好了,扯远了。怎么联接这两张表呢?标准写法:

SELECT * FROM t_student JOIN t_class 

结果这里只截一小部分图,因为笛卡尔乘积后的行数等于两张表的行数乘积,实在太多了。

这里就可以理解表联接的原理了,依次相连再相加。当然其中很多是无效行,为了去除无效的行我们就要用到外键来进行约束。学生表中的_fk与班级表中的_infor相关联:

SELECT * FROM t_student s JOIN t_class c ON s._fk=c._infor; 

结果:

这里通过外键的匹配我们就得到了一张完美的联接之后的表,它可以看做一张新表,想要任何数据均可以从此表中查询,这就是表联接的强大之处。

表联接的分类:

内联接:

内联接是指两个表中某一行相关的列值匹配时,这一行才会出现在表中。就像上例中s._fk与c._infor相同时才会出行该行,其他的行剔除。

语法为INNER JOIN 其中INNER可以省略。

内联接的简写:

SELECT * FROM t_student s,t_class c WHERE c._infor = s._fk 

* 此写法也是我们用的最多的。

外联接:

分为左外联接与右处联接。

外联接是指不管有没有匹配,被定义了外联接的表数据都要出现在结果中。比如左外联接,那么在JOIN左边的表就被定义为外联接,那么此表中所有数据都会出现在查询结果中。
注意班级表中的四班是没有学生的,所以在内联接之后理所当然的被剔除了。现在以外联接做示例:
SELECT * FROM t_student s RIGHT JOIN t_class c ON s._fk=c._infor; 

上面SQL中表t_class在写在JOIN的右边,所以我们用RIGHT JOIN来进行外联接。

最下面多了一行四班的信息

例如我们想查出还没有学生录入的班级信息:

SELECT c._id,c._cname,c._code FROM t_student s RIGHT JOIN t_class c ON s._fk=c._infor WHERE s._id IS NULL; 

这就是外联接的用法,通常用在我们想要的数据匹配不上时。

自联接:

自联接属于内联接或外联接的一种特例,自联接所联接的表均是来自同一张,用法个人感觉还是比较巧妙的。

现有一表如下:

表中,6个人均属于某公司的员工。区别是李四为张三和王五的领导,张八为赵六和孙七的领导。leader_id与work_id相关联。

现在可以通过自联接巧妙的将一张表分为员工部分和领导部分:

SELECT w.work_name,l.work_name 领导姓名 FROM t_emp w,t_emp l WHERE w.leader_id=l.work_id;

注意别名的用法

结果:

是不是有点方便?

知识点罗列到这里,做题时间到:

1.查询凤姐所在的班级

SELECT _cname FROM t_student s,t_class c WHERE c._infor = s._fk AND s._name = '凤姐';

2.查询同朱军同班级的学生

SELECT s._name FROM t_student s WHERE s._fk = (
SELECT cc._infor FROM t_class cc,t_student ss WHERE ss._fk = cc._infor AND ss._name = '朱军'
) AND s._name != '朱军';

本题中,括号内为联接后的表,其返回的是'朱军'所在班级的_infor,然后主查询在学生表中匹配与_infor相等的_fk的行,最后从匹配成功后的行中剔除'朱军'自己。

3.查询每个班级的人数

SELECT d._cname,COUNT(_name) FROM (SELECT ss.*,cc._cname FROM t_class cc LEFT JOIN t_student ss ON ss._fk = cc._infor) d GROUP BY d._cname;

本题中,括号内为班级表外联接后的表,并给该联接后的表以别名d,按d的班级名称d._cname分组后统计各班人数。这里之所以用外联接还是因为四班没有学生但依然要统计。

4.查询班级人数最多的班级

SELECT cc._cname,COUNT(_name) FROM t_class cc,t_student ss WHERE cc._infor = ss._fk GROUP BY cc._cname HAVING COUNT(_name) >=ALL(
SELECT COUNT(_name) FROM t_class c,t_student s WHERE c._infor = s._fk GROUP BY c._cname
);

这个有点凶残,用了两次表联接。括号内返回的是每个班的人数:

之后外部又使用了一次表联接,将每个班的人数与括号内的返回值逐一比较,得到最大值,然后找到最大值所在的班级。这里就体现了对SQL执行顺序的理解有多重要了,联接、分组、过滤等等的先后顺序。

结果:

5.查询每个班中年龄最低的人

SELECT cc._cname,ss._name,ss._age FROM t_student ss,t_class cc WHERE ss._fk = cc._infor AND ss._age <=ALL(
SELECT MIN(s._age) FROM t_student s WHERE ss._fk = s._fk
);

本题中,括号内部返回一个学生表中的最小年龄,外部进行表联接后将年龄列对返回值进行比较,若小于等于返回的最小值那其本身也为最小值。

如果括号内部不加判断条件WHERE ss._fk = s._fk,则最后只会查询出一条年龄最小的数据,而并没有按我们想要的查询出每个班的最小值。

如:

有人会问了既然按班分,用分组不就好了?但要注意的是最小年龄的人不只一个,而分组后每一个班只会显示一个人。所以这里用了关联条件WHERE ss._fk = s._fk来让内外表关联,从而统计出所有我们想要的值。

结果:

UPDATE dbo.BtxCMS_Class_Region SET region_code='new1',ParentPath=
',1,'+CAST(s.region_id AS VARCHAR())+','
FROM dbo.BtxCMS_Class_Region s
WHERE s.ParentID=; UPDATE dbo.BtxCMS_Class_Region SET region_code='new2',ParentPath=
(SELECT ParentPath FROM dbo.BtxCMS_Class_Region WHERE region_id=s.ParentID) + CAST(s.region_id AS VARCHAR())+','
FROM dbo.BtxCMS_Class_Region s
WHERE s.ParentID IN (SELECT region_id FROM dbo.BtxCMS_Class_Region e WHERE region_code='new1'); UPDATE dbo.BtxCMS_Class_Region SET region_code='new3',ParentPath=
(SELECT ParentPath FROM dbo.BtxCMS_Class_Region WHERE region_id=s.ParentID) + CAST(s.region_id AS VARCHAR())+','
FROM dbo.BtxCMS_Class_Region s
WHERE s.ParentID IN (SELECT region_id FROM dbo.BtxCMS_Class_Region e WHERE region_code='new2'); UPDATE dbo.BtxCMS_Class_Region SET region_code='new4',ParentPath=
(SELECT ParentPath FROM dbo.BtxCMS_Class_Region WHERE region_id=s.ParentID) + CAST(s.region_id AS VARCHAR())+','
FROM dbo.BtxCMS_Class_Region s
WHERE s.ParentID IN (SELECT region_id FROM dbo.BtxCMS_Class_Region e WHERE region_code='new3');

sql数据库表连接,主要分为:内连接外连接(左连接、右连接 、全连接)、交叉连接,今天统一整合一下,看看他们的区别。

 
首先建表填充值。
学生表:student(id,姓名,年龄,性别 )
成绩表:score(id,学生id,成绩)
 
一、内连接(inner join……on)
select student.* ,Score.* from student inner join Score on student.id=Score.sid
查询结果如下:
 
关系如下图:
 
总结:inner join取两表的交集。
 
二、外连接
外连接包括 左连接、右连接、全连接  (left|right | full outer join ……on),其中outer可以省略
 
(1)左连接(left join ……on)
select student.* ,Score.* from student left join Score on student.id=Score.sid
查询结果如下:
关系如下图:
总结:left join 以左表为准,查询出左表的所有数据,右表中有对应的则显示出来,没有对应的则显示为null.
注:A left join B on  与  A,B where  有相同效果,如下:
select student.* ,Score.* from student inner join Score on student.id=Score.sid
select student.* ,Score.* from student,Score where student.id=Score.sid
 
 
(2)右连接(right join ……on)
select student.* ,Score.* from student right join Score on student.id=Score.sid
关系如下图:
总结:right join 以右表为准,查询出右表的所有数据,左表中有对应的则显示出来,没有对应的则显示为null.
 
(3)全连接(full join ……on)
select student.* ,Score.* from student full join Score on student.id=Score.sid
总结:full join 是为left和right的集合,某表中某一行在另一表中无匹配行,则相应列的内容为NULL。
 
三、交叉连接(cross join),注意没有on条件
select student.* ,Score.* from student cross join Score

叉联接也称作笛卡尔积。相当于两个表中的所有行进行排列组合。

若表a有X行,表b有Y行,则将返回XY行记录。

SQL语句汇总(终篇)—— 表联接与联接查询的更多相关文章

  1. 2019-1-11 SQL语句汇总——聚合函数、分组、子查询及组合查询

  2. 基本Sql语句汇总

    关于Sql语句的学习,选择的DBMS为SQL Server,Sql语句随着工作中的应用不断补充,不具备系统性,为个人笔记汇总,网上有很多优秀的资源,故不对每一处应用做过多细致的说明,后期会对部分篇幅较 ...

  3. 使用SQL语句清空数据库所有表的数据

    使用SQL语句清空数据库所有表的数据 近来发现数据库过大,空间不足,因此打算将数据库的数据进行全面的清理,但表非常多,一张一张的清空,实在麻烦,因此就想利用SQL语句一次清空所有数据.找到了三种方法进 ...

  4. 使用sql语句复制一张表

    如何使用sql语句复制一张表? 方法一:第一步:先建一张新表,新表的结构与老表相等. create table newbiao like chengjibiao(老表名); 第二步:将老表中的值复制到 ...

  5. sql 语句 获取某张表某列字段最短的某几行数据

    sql 语句 获取某张表某列字段最短的某几行数据 SELECT C_name,C_code FROM Catalog where LEN(C_code)=LEN((SELECT top 1 C_cod ...

  6. 使用Sql语句快速将数据表转换成实体类

    开发过程中经常需要根据数据表编写对应的实体类,下面是使用sql语句快速将数据表转换成对应实体类的代码,使用时只需要将第一行'TableName'引号里面的字母换成具体的表名称就行了: declare ...

  7. 查看oracle的sql语句历史记录和锁表的情况

    查看oracle的sql语句历史记录和锁表的情况 (2012-01-04 20:59:59) 转载▼ 标签: 杂谈 分类: database 查询sql的历史记录 select * from v$sq ...

  8. 使用sql语句备份一张表

    如何使用sql语句复制一张表? 方法一:第一步:先建一张新表,新表的结构与老表相等. create table newtable like oldtable; 第二步:将老表中的值复制到新标中. in ...

  9. 如何用sql语句复制一张表

    如何用sql语句复制一张表 1.复制表结构及数据到新表 CREATE TABLE 新表 SELECT * FROM 旧表 这种方法会将oldtable中所有的内容都拷贝过来,当然我们可以用delete ...

随机推荐

  1. apache-jmeter学习文档

    http://www.cnblogs.com/TankXiao/p/4045439.html#sampler

  2. 几篇关于VisualStudio的调试工具文章

    现代的软件变得日益复杂,强大的调试功能也变得日益重要起来.在VisualStudio的最近几个版本中,在调试工具方面也是增强了不少的,本文转录了几个微软官方介绍的一些新增的调试功能的文章,如果能很好的 ...

  3. Java、Android 开发环境搭建

    一.准备工作 为便于管理,将java开发工具集中到一个文件夹中.创建D:\javaDevE文件夹,JDK.Android-SDK.Eclipse.tomcat等都可以安装到这个文件夹中. 二.搭建Ja ...

  4. XidianOJ 1183 Water Problem: Items divided

    题目描述 Youyouyouyou is very interested in math, one day, an idea came into his mind that how many ways ...

  5. mysql——查询练习

    Sutdent表的定义 字段名 字段描述 数据类型 主键 外键 非空 唯一 自增 Id 学号 INT(10) 是 否 是 是 是 Name 姓名 VARCHAR(20) 否 否 是 否 否 Sex 性 ...

  6. Redis 的Lua Script脚本功能

    从 Redis 2.6.0 版本开始,通过内置的 Lua 解释器,可以使用 EVAL 命令对 Lua 脚本进行求值 Redis2.6内置的Lua Script支持,可以在Redis的Server端一次 ...

  7. C# 中的IOCP线程池

    原文地址:http://www.theukwebdesigncompany.com/articles/iocp-thread-pooling.php PartOne : Introduction 当使 ...

  8. PLAN表

    用得较多的PLAN表有以下三个ABPPMGR:MANUFACTURINGPLN.SHIPMENTPLAN.PROCUREMENTPLAN .这三个表都是执行StartFP中的exportFP进行数据导 ...

  9. python学习笔记3-celery分布式任务处理器

    celery是用python写的一个异步的任务框架,功能非常强大,具体的说明可以查看官网,这里主要提供点demo让你迅速使用该框架   1.环境安装 默认安装好了redis pip install c ...

  10. linux 的 samba 实现共享文件夹

    samba Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成. service XXX start 失败多是权限不够,使用管理员权限尝试