中国统计网 SQL太难?你离完全理解SQL就差这10步!( 三 )


EXISTS比IN的表达性更好(更适合复杂的语句)
二者之间性能没有差异(但对于某些数据库来说性能差异会非常大)
--FindonlythoseauthorswhoalsohavebooksSELECTDISTINCTfirst_name,last_nameFROMauthorJOINbookONauthor.id=book.author_id这是一种很糟糕的写法 , 原因如下:SQL语句性能低下:因为去重操作(DISTINCT)需要数据库重复从硬盘中读取数据到内存中 。 (译者注:DISTINCT的确是一种很耗费资源的操作 , 但是每种数据库对于DISTINCT的操作方式可能不同) 。
这么写并非完全正确:尽管也许现在这么写不会出现问题 , 但是随着SQL语句变得越来越复杂 , 你想要去重得到正确的结果就变得十分困难 。
ANTIJOIN这种连接的关系跟SEMIJOIN刚好相反 。 在IN或者EXISTS前加一个NOT关键字就能使用这种连接 。 举个例子来说 , 我们列出书名表里没有书的作者:--UsingINFROMauthorWHEREauthor.idNOTIN(SELECTbook.author_idFROMbook)--UsingEXISTSFROMauthorWHERENOTEXISTS(SELECT1FROMbookWHEREbook.author_id=author.id)关于性能、可读性、表达性等特性也完全可以参考SEMIJOIN 。 这篇博文介绍了在使用NOTIN时遇到NULL应该怎么办 , 因为有一点背离本篇主题 , 就不详细介绍 , 有兴趣的同学可以读一下CROSSJOIN这个连接过程就是两个连接的表的乘积:即将第一张表的每一条数据分别对应第二张表的每条数据 。 我们之前见过 , 这就是逗号在FROM语句中的用法 。 在实际的应用中 , 很少有地方能用到CROSSJOIN , 但是一旦用上了 , 你就可以用这样的SQL语句表达:--CombineeveryauthorwitheverybookauthorCROSSJOINbookDIVISIONDIVISION的确是一个怪胎 。 简而言之 , 如果JOIN是一个乘法运算 , 那么DIVISION就是JOIN的逆过程 。 我们学到了什么?让我们在脑海中再回想一下 。 SQL是对表的引用 , JOIN则是一种引用表的复杂方式 。 但是SQL语言的表达方式和实际我们所需要的逻辑关系之间是有区别的 , 并非所有的逻辑关系都能找到对应的JOIN操作 , 所以这就要我们在平时多积累和学习关系逻辑 , 这样你就能在以后编写SQL语句中选择适当的JOIN操作了 。7
SQL中如同变量的派生表
在这之前 , 我们学习到过SQL是一种声明性的语言 , 并且SQL语句中不能包含变量 。 但是你能写出类似于变量的语句 , 这些就叫做派生表:说白了 , 所谓的派生表就是在括号之中的子查询:FROM(SELECT*FROMauthor)派生表可以有效的避免由于SQL逻辑而产生的问题 。 举例来说:如果你想重用一个用SELECT和WHERE语句查询出的结果 , 这样写就可以(以Oracle为例):--Getauthors'firstandlastnames,andtheirageindaysSELECTfirst_name,last_name,ageFROM(SELECTfirst_name,last_name,current_date-date_of_birthageFROMauthor)--Iftheageisgreaterthan10000daysWHEREage>10000需要我们注意的是:在有些数据库 , 以及SQL:1990标准中 , 派生表被归为下一级——通用表语句(commontableexperssion) 。 这就允许你在一个SELECT语句中对派生表多次重用 。 上面的例子就(几乎)等价于下面的语句:WITHaAS(SELECTfirst_name,last_name,current_date-date_of_birthageFROMauthor)SELECT*FROMaWHEREage>10000我们学到了什么?我们反复强调 , 大体上来说SQL语句就是对表的引用 , 而并非对字段的引用 。 要好好利用这一点 , 不要害怕使用派生表或者其他更复杂的语句 。8
SQL语句中GROUPBY是对表的引用进行的操作
让我们再回想一下之前的FROM语句:FROMa,b现在 , 我们将GROUPBY应用到上面的语句中:GROUPBYA.x,A.y,B.z上面语句的结果就是产生出了一个包含三个字段的新的表的引用 。 我们来仔细理解一下这句话:当你应用GROUPBY的时候 , SELECT后没有使用聚合函数的列 , 都要出现在GROUPBY后面 。 (译者注:原文大意为“当你是用GROUPBY的时候 , 你能够对其进行下一级逻辑操作的列会减少 , 包括在SELECT中的列”) 。 需要注意的是:其他字段能够使用聚合函数:SELECTA.x,A.y,SUM(A.z)FROMAGROUPBYA.x,A.y还有一点值得留意的是:MySQL并不坚持这个标准 , 这的确是令人很困惑的地方 。 译者注:这并不是说MySQL没有GROUPBY的功能)但是不要被MySQL所迷惑 。 GROUPBY改变了对表引用的方式 。 你可以像这样既在SELECT中引用某一字段 , 也在GROUPBY中对其进行分组 。 我们学到了什么?GROUPBY , 再次强调一次 , 是在表的引用上进行了操作 , 将其转换为一种新的引用方式 。9


推荐阅读