T-SQL基础(二)之关联查询

在上篇博文中介绍了T-SQL查询的基础知识,本篇主要介绍稍微复杂的查询形式。

表运算符

表运算符的作用是把为其提供的表作为输入,经过逻辑查询处理,返回一个表结果。SQL Server支持四个表运算符:JOIN、APPLY、PIVOT、UNPIVOT,其中JOIN是标准SQL中的运算符,APPLY、PIVOT和UNPIVOT是T-SQL的扩展。

JOIN:联接查询时使用

APPLY:用于FROM子句中,分为CROSS APPLYOUTER APPLY两种形式

PIVOT:用于行转列

UNPIVOT:用于列传行

联接查询

联接查询分为外联接、内联接、交叉联接,三者的区别在于如何应用逻辑查询处理阶段:

  • 交叉联接仅应用一个阶段——笛卡尔乘积;
  • 内联接应用两个阶段——笛卡尔乘积和基于谓词ON的筛选;
  • 外联结应用三个极端——笛卡尔乘积,基于谓词ON的筛选,添加外部行;

内部行 & 外部行

内部行指的是基于谓词ON与另一侧匹配的行,外部行则是未匹配的行,外部行用NULL进行填充。内联接结果集仅保留内部行,外联接结果集返回内部行和外部行。

笛卡尔乘积

将一个输入表的每一行与另一个表的所有行匹配,即,如果一张表有m行a列,另一张表n行b列,笛卡尔乘积后得到的表有mn行,a+b列*。由此可以看出,对于数据量较大的表进行关联的话,会得到一张数据量更大的表,会有可能造成内存溢出的。

以下是网络上关于笛卡尔乘积的解释:

在数学中,两个集合X和Y的笛卡儿积(Cartesian product),又称直积,表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员。假设集合A=a, b,集合B=0, 1, 2,则两个集合的笛卡尔积为(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)。类似的例子有,如果A表示某学校学生的集合,B表示该学校所有课程的集合,则A与B的笛卡尔积表示所有可能的选课情况。A表示所有声母的集合,B表示所有韵母的集合,那么A和B的笛卡尔积就为所有可能的汉字全拼。

举例如下:

USE WJChi;

SELECT * FROM dbo.UserInfo;
SELECT * FROM dbo.UAddress;

SELECT * 
FROM dbo.UserInfo 
CROSS JOIN dbo.UAddress;

得到结果集如下:

交叉联接

SQL中使用CROSS JOIN语句进行交叉联接查询,在逻辑处理上,交叉联接是最为简单的联接类型,它只获取表的笛卡尔乘积。

交叉联接两种写法:

USE WJChi;

-- 使用CROSS JOIN,推荐使用这种方式
SELECT * 
FROM dbo.UserInfo 
CROSS JOIN dbo.UAddress;

-- 不使用CROSS JOIN
SELECT * 
FROM dbo.UserInfo,dbo.UAddress;

内联接

SQL中使用INNER JOIN...ON...语句进行内联接查询,INNER关键字可选。内联接的逻辑处理分为两步:

  • 生成笛卡尔乘积
  • 根据谓词ON对笛卡尔乘积进行筛选

与交叉联接一样,内联接有两种写法:

USE WJChi;

-- 使用JOIN,推荐使用这种方式
SELECT * 
FROM dbo.UAddress
JOIN dbo.UserInfo 
ON UserInfo.UAddressId = UAddress.Id;

-- 不使用JOIN,与交叉联接类似,但比交叉联接多了WHERE条件
SELECT * 
FROM dbo.UAddress,dbo.UserInfo 
WHERE UserInfo.UAddressId = UAddress.Id;

外联接

外联接分为左外联接:LEFT OUT JOIN、右外联接:RIGHT OUT JOIN和全联接:FULL OUT JOIN,其中,OUT关键字是可选的。相比于交叉联接和内联接,外联接则最为复杂。外联接逻辑处理分为三步:

  1. 获取表的笛卡尔乘积
  2. 根据谓词ON对笛卡尔乘积进行筛选
  3. 添加外部行数据到结果集中
LEFT JOIN & RIGHT JOIN

LEFT JOIN获取的结果集中保留了左表(LEFT JOIN左侧的表)中的所有数据,及右表中满足筛选条件的数据。右表中不满足筛选条件的空行(外部行)则用NULL值填充。

RIGHT JOINLEFT JOIN作用相反。

示例代码如下,表UserInfo中有4条数据,表UAddress中有三条数据:

USE WJChi;

SELECT * 
FROM dbo.UAddress
LEFT JOIN dbo.UserInfo 
ON UserInfo.UAddressId = UAddress.Id;

SELECT * 
FROM dbo.UAddress
RIGHT JOIN dbo.UserInfo 
ON UserInfo.UAddressId = UAddress.Id;

查询结果如下:

FULL JOIN

FULL JOIN的结果是取LEFT JOINRIGHT JOIN查询结果集的并集

USE WJChi;

SELECT * 
FROM dbo.UAddress
FULL JOIN dbo.UserInfo 
ON UserInfo.UAddressId = UAddress.Id;

查询结果如下:

ON & WHERE

前面说到:内联接结果集仅保留内部行,外联接结果集返回内部行和外部行。换句话说,外联接中ON子句的作用是进行表之间关联,如果外联接需要对结果集做进一步的筛选的话不能使用ON...AND...语句,而要使用WHERE条件。示例如下:

USE WJChi;

-- 内联接使用ON...AND...筛选数据
SELECT * 
FROM dbo.UserInfo AS UI
JOIN dbo.UAddress AS UA
ON UA.Id = UI.UAddressId 
-- 获取Name为xfh的数据
AND UI.Name='xfh';

-- 外联接使用ON...AND...筛选数据
SELECT * 
FROM dbo.UserInfo AS UI
LEFT JOIN dbo.UAddress AS UA
ON UA.Id = UI.UAddressId 
-- 获取Name为xfh的数据,无效
AND UI.Name='xfh';

-- 外联接使用WHERE对结果集进行筛选
SELECT * 
FROM dbo.UserInfo AS UI
LEFT JOIN dbo.UAddress AS UA
ON UA.Id = UI.UAddressId 
WHERE UI.Name='xfh';

输出结果如下:

复合联接

复合联接是指谓词涉及表中多个字段的联接,即,关联条件使用ON...AND...的形式。

自联接

同一张表的多个实例之间相互联接,称为自联接。所有基本联接类型(内联接、外联接、交叉联接)支持。

USE WJChi;

SELECT * 
FROM dbo.UserInfo AS U1 
CROSS JOIN dbo.UserInfo AS U2;

自联接中要为表名指定别名,否则结果集中的列名都将不明确。

相等联接 & 不等联接

当联接条件使用相等运算符时称为相等联接,否则称为不等联接:

USE WJChi;

-- 相等联接
SELECT * 
FROM dbo.UAddress
FULL JOIN dbo.UserInfo 
ON UserInfo.UAddressId = UAddress.Id;

-- 不等联接
SELECT * 
FROM dbo.UAddress
FULL JOIN dbo.UserInfo 
ON UserInfo.UAddressId <> UAddress.Id;

多联接查询

超过两张表进行关联查询即为多联接查询。通常,当SQL中出现多个表运算符时,从左到右进行逻辑处理,前一个联接的结果会作为下一个联接的左侧输入。SQL Server也常常出于优化查询的目的,在实际处理查询过程中对联接进行重新排序,但这不会影响到处理结果集的正确性。

:warning:不建议超过三张表进行关联,过多的表关联会使SQL变得复杂,难以维护且影响性能

小结

过多的表联接会让SQL逻辑变得复杂,对查询性能产生负面影响,且难以维护。

SQL(任何代码)的书写应将语义清晰作为第一追求,而不是为了“炫技”写一些别人难以理解的代码。

StackOverflow中扣出的一张图片,可以概述外联接和内联接查询:

推荐阅读

T-SQL基础(一)之简单查询

What is the difference between “INNER JOIN” and “OUTER JOIN”?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容