SQL 中不同类型的表连接

http://www.linuxidc.com/Linux/2012-08/68035.htm

1、简介

在关系型数据库中,join操作是将不同的表中的数据联合在一起时非常通用的一种做法。首先让我们看看join是如何操作的,然后我们探索一下当join和where语句同时存在的时候的执行顺序问题,最后来谈一谈不同类型的join的顺序问题。

2、建立初始的测试表结构(建表语句到这里下载

表建立完之后,将会看到如下三个表。

我们将通过以上三个表来演示join操作。这三个表都是用来做演示的,所以我并没有使用主键和外键。

3、表的笛卡尔乘积

一般情况下,我们使用两个表中的相关字段进行join操作,例如,employee表中的DeptId字段对应于Department表中的DepId字段,通过这种方式进行join。

下面的一个例子是不使用关联字段来做表的连接。这里TableA和TableB以笛卡尔乘积的方式连在了一起。笛卡尔乘积就是先从第一个表中取出一条记录,和第二章表中的每一条记录配合,然后再取出第二条记录,同样和第二张表的所有记录配合,直至第一张表中的所有记录都取完。所以最终的结果数量将是两张表的乘积。

4、join两张表

当我们想做两个表的连接,而不是像上面的例子一样得到大量的无用的结果的时候,我们就得从两张表中选取一个join列。我下面给出的例子是使用id作为join列的。我们可以通过这种方式使得结果只映射我们需要的那一部分,从而过滤掉了无用数据。

注意:在笛卡尔乘积表中的第一行和第五行满足了join的映射关系,从而被作为结果,其他的都被过滤掉了。

5、join多张表

上面的例子是join两张表,如果想join多张表,我们需要在上面的结果中选择一列,然后再在新表中选择一列,将这两者作为join字段,然后指定join的规则,这样我们理论上可以join任意多张表。

首先,Table_A和Table_B做了连接,就上上面的join两张表的例子,然后将join的结果作为一张表AB。再将AB与Table_C连接。

6、join类型

在两张不同的表做连接有3中join类型。

1、full join
2、inner join
3、outer join(left outer join、right outer join)

在上面两个例子中我们看到的是inner join。如果我们连接表自身就叫做self join。这个特殊类型不会混淆连接类型。

7、full join

full join和笛卡尔有些不同,笛卡尔积会获取所有可能的结果。而full join将匹配的结果与所有左边的表中不匹配右边的行和右边的表中所有不匹配左边的行加在一起,在不匹配的地方使用NULL代替。结果行数=匹配行数+左表剩余行数+右表剩余行数。

在上面的图片中,蓝色的行是两个表匹配的行。

第二行,左边绿色,右边红色的是不匹配的,左表中的行是存在的,而右表中的字段则被null填充。

第三行,左边红色,右边绿色的同样是不匹配的,右表中的行是存在的,而左表中的字段则被null填充。

8、left join

左连接(left join)保证左表中的所有行都有,而当不匹配的时候以NULL填充右表字段。

蓝色匹配,红色和绿色不匹配

9、right join

反过来,右连接(right join)保证右表中所有的行都有,而当不匹配的时候以NULL填充左表字段。

蓝色匹配,红色和绿色不匹配

10、inner join

inner join就是只列出匹配的行。

11、self join

表连接自身叫做self join。为了解释一下这个让我们看如下图中的employee表。EmployeeID是此表的主键,ReportsTo引用了此表的主键。我们可以想象成这样,ReportTo字段引用代表该雇员的上司,其上司同样也是雇员。

看如下例子

这里,有ReportTo指向的行是Manager,所以employee是左表,Manager是右表。

12、执行顺序

当连接中有where语句的时候我们需要注意连接和where的执行顺序问题。
1、将where语句先于join执行,因为执行完where查询的结果将会比较少,从而join操作性能会提升。
2、将where语句后与join执行。
以上两者将在inner join的时候返回同样的结果,但是当使用outer join的时候至少有一种连接操作的返回结果不同。看下面例子。

所以记住当外连接的时候尽量先执行join操作然后执行where语句。

13、连接的顺序

当你想将inner join和outer join同时使用的时候join的顺序也是非常重要的。

什么是连接的顺序?如果我像这样连接三张表【X inner Y】left Z,顺序就是先inner join再left join。

让我们回到上面的例子中,你想得到的结果是获取所有客户的名字,不管他们是否有订单。如果他们确实有一些订单,还要列出了客户订购的数量。
看如下的查询【先outer join再inner join】

1、在Orders和Customers中进行了right join。右连接能保证你获取所有Customer的信息,不管他是否有order。
2、现在上面的结果将和Order Details连接。但是我们需要注意的是,在右连接的结果中有两行roderid为null的,因为这两个customer并没有任何order,而在后面做inner join的时候,由于orderid为null,inner join将跳过这两行,从而导致这两个customer的信息被过滤掉了。
再让我们看看下面的这个查询【先inner join再outer join】

让我们分析一下为什么这才是我们想要的结果。

首先Order和Order Details表做inner join,所有匹配的结果都将被列出来,然后将此结果作为左表,Customer表作为右表,右表的所有行都将被列出来,不管其匹配与否(言外之意,那两个没有order的customer也将被列出来)。

所以,在我们同时使用inner join和outer join的时候一定要对连接的顺序做慎重考虑。

14、获取同样数据的其他办法

看如下查询

1、首先查询出Customers将其作为左表
2、然后将Orders表查询出来,仍然作为左表
3、然后查询出Order Details表将其作为右表与Orders表进行inner join。
4、最后Customers表将于第三步查询出的结果进行左连接。别忘了左连接将保证Customers表不丢失任何记录。

时间: 2024-10-07 03:59:59

SQL 中不同类型的表连接的相关文章

SQL中查看数据库各表的大小

SQL中查看数据库各表的大小 编写人:CC阿爸 2014-6-17 在日常SQL数据库的操作中,如何快速的查询数据库中各表中数据的大小. 以下有两种方法供参考: 第一种: create table #t(name varchar(255), rows bigint, reserved varchar(20), data varchar(20), index_size varchar(20), unused varchar(20)) exec sp_MSforeachtable "insert i

如何在SQL中产生交叉式数据表(枢纽分析表)Part 2(PIVOT,UNPIVOT)

之前小喵使用SQL2000的时候,为了产生交叉数据表(Excel中称为枢纽分析表),小喵用了以下这篇的方式来处理 http://www.dotblogs.com.tw/topcat/archive/2008/04/14/2909.aspx 这样的方式在SQL 2005里面一样可以用,不过2005又新增了一个更方便的东西,可以更简洁的来处理.这个东西就是[PIVOT],神奇的是,除了可以透过PIVOT产生交叉数据表,还可以透过UNPIVOT将交叉数据表转回原来的方式(这对于有些数据表的正规化很有帮

MySQL中的基本多表连接查询 转自脚本之家(作者:真实的归宿)

一.多表连接类型 1. 笛卡尔积(交叉连接) 在MySQL中可以为CROSS JOIN或者省略CROSS即JOIN,或者使用','  如: 由于其返回的结果为被连接的两个数据表的乘积,因此当有WHERE, ON或USING条件的时候一般不建议使用,因为当数据表项目太多的时候,会非常慢.一般使用LEFT [OUTER] JOIN或者RIGHT [OUTER] JOIN 2.   内连接INNER JOIN 在MySQL中把I SELECT * FROM table1 CROSS JOIN tabl

SQL中的CTE通用表表达式

开发人员正在研发的许多项目都涉及编写由基本的 SELECT/FROM/WHERE 类型的语句派生而来的复杂 SQL 语句.其中一种情形是需要编写在 FROM 子句内使用派生表(也称为内联视图)的 Transact-SQL (T-SQL) 查询.这一常规使开发人员能获取一个行集,并立即将该行集加入到 SELECT 语句中的其他表.视图和用户定义函数中.另一种方案是使用视图而不是派生表.这两种方案都有其各自的优势和劣势. 当使用 SQL Server™ 2005 时,我更倾向于第三种方案,就是使用通

ORA-03113 SQL中select语句全表扫描带来的异常

今天在ERP系统的维护过程中,业务人员反馈了一个问题过来,是ERP系统生产单模块的预览打印报表出错,看到后我逐步做了以下的排查: 1.尝试其他单据是否存在相同问题 2.直接打开水晶报表,将参数代入看看是否是报表问题 排查之后逐渐发现,问题出在数据源身上,找到返回数据集的存储过程,进入测试窗口检查是否运行正常,结果发现运行即进入卡死状态,进程无法中断,只好强行退出PL/SQL,这时候我估计到问题出在SQL语句上,因此将SQL语句复制到新的窗口,代入参数,如下: SELECT WO_NBR,WO_L

SQL中使用关键词创建表或字段

有时候我们给表或者字段命名时,会无意中选择了一个SQL中的关键字进行命名,然后就报错了: ERROR:  syntax error at or near "limit" MySQL解决方法: 在MySQL中需要添加 `` create table `order` (id int, `limit` int); # 由于order和limit都是MySQL中的关键字,必须加上``才能使用 PostgreSQL解决方法: 在PostgreSQL中需要添加 "" creat

帆软SQL报异常:多表连接的时候出现错误:未明确定义列

我刚开始的代码: 1 select 2 dm_veh_jdcgz_mx.DAY_ID ,--日期 3 dm_veh_jdcgz_mx.GLBM ,--管理部门ID 4 dm_veh_jdcgz_mx.SFZMHM ,--身份证号码 5 dm_veh_jdcgz_mx.DSRXM ,--姓名 6 dm_veh_jdcgz_mx.GZTS,--备注 7 8 dim_bas_gzzl.GZZL_MC ,--管理部门名称 9 10 dim_bas_glbm.GLBMMC ,--管理部门名称 11 dim

Sql Server系列:多表连接查询

连接查询是关系数据中最主要的查询,包括内连接.外连接等.通过连接运算符可以实现多个表查询.内连接查询操作列出与连接条件匹配的数据行,它使用比较运算符比较被连接列的列值.SQL Server中的内连接有:等值连接和不等连接. 1. 内连接-相等连接 相等连接又叫等值连接,在连接条件这使用等号(=)运算符比较被连接列的列值,其查询结果中列出被连接表中的所有列,包括其中的重复列. 示例: SELECT [dbo].[Category].* , [dbo].[Product].* FROM [dbo].

关于SQL中CTE(公用表表达式)(Common Table Expression)的总结

WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到 一.WITH AS的含义 WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候,是为了让SQL语句的可读性更高些, 也有可能是在UNION ALL的不同部分,作为提供数据的部分. 特别对于UNION ALL比较有用.因为UNION