子查询与多表连接查询的抉择
1.当连接的两个表中的记录很多时,笛卡尔积运算会造成死机。于是如果要用join语句连接查询,可以先查看涉及到的表的记录数。利用统计记录行数的函数count()查看所关联的表笛卡尔积后的行数:select count(*) from 表1,表2;
2.如果查到的记录数不算太大,则可进行多表连接查询。否则,如果数据量太大的话,应选用子查询的方式。
-
子查询的SQL写法比连接查询的写法复杂,常用到in、any、all和exists等关键字,和比较运算符。
-
Where子句中的子查询,一般返回单行单列、多行单行或单行多列数据记录。
-
from子句中的子查询,一般返回多行多列数据记录,可以当作一张临时表。
一、理解子查询
子查询也称为嵌套查询(Nested Query),即是嵌套在外层查询的WHERE子句中的查询,有时也会嵌套在HAVING的条件中或from子句中。子查询为主查询返回其所需数据, 或者对外查询的查询结果作进一步的限制。每一个SELECT-FROM-WHERE语句称为一个查询块.
SELECT ... FROM 表名 --- 主査询,外层查询
WHERE
(SELECT ... FROM table WHERE ...);--- 子査询,内层査询
即where条件中又有select语句,称为子查询或嵌套查询
二、使用关系运算符和带IN的子查询
内层查询返回列col_name的值,然后外层查询意义相同的列colname和子查询的返回值做比较。使用关系运算符(可以是=、<、<=、>、>=、!=、<>) 时,子查询的返回值至多一个;当使用IN时,子查询的返回值可以有多个。
SELECT ... FROM 表名1
WHERE 列名col_name 关系运算符 | IN | NOT IN
(SELECT 列名col_name FROM 表名2 WHERE ...);
三、单行子查询:
单行子查询包括单行单列子查询和单行多列子查询。可用>、 <、 =和!=连接后边子查询,要求括号中返回的结果为某单一值。
1.单行单列子查询
子查询一般会在主查询语句的Where子句中。
单行单列子查询,也称为稀疏子查询 稀疏子查询是期待在子查询中单一返回值的嵌套查询
2.单行多列子查询
子查询中可以返回单行多列的数据记录,但此类子查询用途较少。
四、多行子查询:
1、多行单列子查询
多行单列子查询可用in, not in来连接后边的子查询,括号中返回的结果为多个值(的集合)。
多行子查询包括多行单列子查询和多行多列子查询。
(1). 带有关键字in的子查询:
当主查询的条件是子查询的结果中的值时,就可以通过关键字in来进行判断。相反当主查询的条件不是子查询的结果中的值时,就可以通过关键字 not in来进行判断。
(2). 带有关键字not in的子查询:
带in的子查询总结
1.带in的子查询中,内查询和外查询必须使用意义相同的字段来构造条件;
-
如果内查询的结果只有一个返回值,则可以用关系运算符或者in来构造条件;
-
如果内查询的结果有多个返回值,则必须只能用in来构造条件。
带ANY、SOME、ALL的子查询
使用带some、any或all的子查询来构造查询条件时,some、any或all的前面必须加上关系运算符,
如大于、等于或小于等。
ANY 和 SOME 同义,为某个之意。在进行比较运算时只要子查询的查询结果 中有某一行能使结果为 True, 则子查询结果就为True;
而ALL则要求子查询中的所有行都使结果为 True 时,子查询结果才为 True。
SELECT 字段名 FROM 表名1
WHERE 字段名 关系运算符 [ANY | SOME | ALL]
(SELECT 字段名 FROM 表名2 WHERE ...);
注:关系运算符可以是<=、<、=、>、>=、!=、<>。
(3). 带有关键字any的子查询:
当主查询的条件是满足子查询的结果中的某条记录时,用带有关键字any的子查询。关键字any或some有三种匹配方式,分别为:
① = any:其功能与关键字in一样;
② > any(或>= any):为大于(或>=)子查询中返回数据中某个即可 ;即比子查询中返回数据记录中最小的要大(或>=);
③ < any (或<= any):为小于(或<=)子查询中返回数据中某个即可 ;即比子查询中返回数据记录中最大的要小(或<=) ;
(4). 带有关键字some 的子查询:
关键字some与any完全相同,有三种匹配方式,分别为:
① > some (或>=some):为大于(或>=)子查询中返回数据中的某个 ;即比子查询中返回数据记录中最小的大(或>=)即可;
② <some (或<= some ):为小于(或<=)子查询中返回数据中的某个;即比子查询中返回数据记录中最大的小(或<=)即可;
③ = some:为子查询中返回数据中某一个。
(5). 带有关键字all 的子查询:
当主查询的条件是满足子查询的结果中的所有记录时,可用带有关键字all的子查询。
关键字all 有两种匹配方式,分别为:
① > all (或>= all):为大于(或>=)子查询中返回数据中所有的 ;即比子查询中返回数据记录中最大的还要大于(或>=)的数据记录 ;
②< all (或<= all ):为小于(或<=)子查询中返回数据中所有的;即比子查询中返回数据记录中最小的还要小(或<=)的数据记录 ;
(6).带有关键字exists 的子查询:
EXISTS (一个子查询),是检测子查询的行是否存在数据,即子查询的结果是不是空集。
SELECT... . FROM table WHERE EXISTS (subquery)
EXISTS 用于检查子查询是否至少会返回一行数据,该子查询实际上并不取返回的任何数据,而是要返回值True或False 。将主查询的数据,放到子查询中做条件验证,根据验证结果(TRUE或FALSE )来决定主查询的数据结果是否得以保留。.在子查询中使用 NULL 仍然返回结果集,通过使用 EXISTS 仍取值为 TRUE。
subquery 是一个受限的SELECT 语句(不允许有COMPUTE 子句和INTO关键字)。如果子查询至少包含一行,则返回TRUE。
如果子查询有元组,即非空,则exists 返回true
exists r r ≠ Ø not exists r r = Ø
- 带exists的子查询,只检查子查询中有没有结果返回。如果是空集则不执行,如果有值,则执行。
- 子查询的结果并不参与比较,所以exists的前面不加任何关系运算符(如大于、等于或小于等)。
2、多行多列子查询:
当子查询的返回结果为多行多列数据记录时,该子查询语句一般会在主查询语句的from子句里,被当作一张临时表的方式来处理。
五、带 EXISTS 的子查询
EXISTS 用来检查子查询是否至少会返回一行数据, 该子查询实际上并不取返回的任何数据, 而是要返回值True或False。只要返回一行, EXISTS 的结果即为 True, 外查询语句执行查询;反之如果返回空集,则结果为 False, 此时外层查询语句将不执行。
将主查询的数据,放到子查询中做条件验证,根据验证结果TRUE或 FALSE)来决定主查询的数据结果是否得以保留。也就是说EXISTS 的意思是子查询中是否存在结果。如果存在则主查询的where条件成立,如果不存在则主查询的where条件不成立。
SELECT 字段名 FROM 表名1
WHERE [EXISTS | NOT EXISTS]
(SELECT ... FROM表名2 WHERE ...);