5. SQL子查询—内嵌的SQL子句

Posted 江湖@小小白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5. SQL子查询—内嵌的SQL子句相关的知识,希望对你有一定的参考价值。

1. 子查询

子查询是一种把查询结果作为参数返回给另外一个查询的一种查询,子查询可以让你多个查询绑定在一起。

2. 建立一个子查询

简而言之,子查询可以让你把查询的结果与另外一个查询绑定在一起。


通用的语法格式:
SELECT * FROM 
TABLE1
WHERE 
TABLE1.SOMECOLUMN =
(
    SELECT 
    SOMEOTHERCOLUMN 
    FROM 
    TABLE2
	WHERE 
    SOMEOTHERCOLUMN = SOMEVALUE
)



使用 ORDERS 和 PART 表来举一个实例:
两表的共有字段是 PARTNUM,
假如你不知道,
或者是不想知道这个字段,
但是你又想用 PART 表的 description 字段来工作,
这时可以使用子查询.

eg1:
SELECT * FROM 
ORDERS 
WHERE 
PARTNUM =
(
    SELECT 
    PARTNUM
    FROM 
    PART 
    WHERE 
    DESCRIPTION 
    LIKE 
    "ROAD%"
)


eg2:
SELECT 
O.ORDEREDON,
O.PARTNUM,
P.DESCRIPTION,
O.QUANTITY,
O.REMARKS
FROM 
ORDERS O,
PART P
WHERE 
O.PARTNUM = P.PARTNUM
AND 
O.PARTNUM =
(
    SELECT 
    PARTNUM
    FROM 
    PART
	WHERE 
    DESCRIPTION 
    LIKE
    "ROAD%"
)

分析:
O.PARTNUM = P.PARTNUM:
它是 ORDERS 与 PART 表进行归并的标准语句,
如果没有使用 WHERE 子句,
那么你将会得到两个表的记录的所有可能的组合.

子查询如下:
AND 
O.PARTNUM =
(
    SELECT 
    PARTNUM
    FROM 
    PART
	WHERE 
    DESCRIPTION 
    LIKE
    "ROAD%"
)

增加的限制是使你的 PARTNUM 内容必须
与你的子查询所返回的结果相等.

注:
如果你想使用比较运算符如 > <=,
你必须确保你的查询结果是唯一的.


eg3:
SELECT 
O.ORDEREDON,
O.PARTNUM,
P.DESCRIPTION,
O.QUANTITY
O.REMARKS,
FROM ORDERS O,
PART P 
WHERE 
O.PARTNUM = P.PARTNUM
AND 
O.PARTNUM = 
(
    SELECT 
    PARTNUM
    FROM 
    PART
	WHERE 
    DESCRIPTION = "ROAD BIKE"
)


总结:
这个子查询将会返回唯一的结果,
因为使用=会返回唯一的结果,
当你需要唯一的结果时,
如何才能避免子查询返回多个结果呢?

首先是不要使用 LIKE,
再就是设计表的时候就要保证你要搜索的字段内容是唯一的,
你可以使用表自我归并的方法,
来检查给定字段的内容是否是唯一的,
如果表是你自己设计的,
你要让你搜索的列是表中的唯一列,
你也可以使用 SQL 只返回单一结果的部分 — 汇总函数


3. 在子查询中使用汇总函数

像 SUM、AVG、COUNT、MIN 和 MAX 等汇总函数均返回单一的数值。


1. 查询定单的平均金额:
	SELECT 
	AVG(O.QUANTITY * P.PRICE)
	FROM 
	ORDERS O, 
	PART P
	WHERE 
	O.PARTNUM = P.PARTNUM;
	
2. 查询都有哪些定单的金额高于平均值:
	SELECT 
	O.NAME,
    O.ORDEREDON,
    O.QUANTITY * P.PRICE TOTAL,
	FROM ORDERS O,
    PART P 
    WHERE 
    O.PARTNUM = P.PARTNUM 
    AND
	O.QUANTITY * P.PRICE > 
	(
        SELECT 
        AVG(O.QUANTITY * P.PRICE)
		FROM 
        ORDERS O,
        PART P 
        WHERE 
        O.PARTNUM = P.PARTNUM
    )
	
注:
大多数子查询都是作为独立查询,
经过测试确定其只返回一个值以后才作为子查询使用的.


4. 子查询的嵌套

嵌套就是将一个查询嵌入另一个子查询中去。子查询可被嵌套的深度依你的需要而定。


1. 查询花费超过了平均价格的客户:
	SELECT 
	ALL C.NAME,
    C.ADDRESS,
    C.STATE,
    C.ZIP
    FROM 
    CUSTOMER C
	WHERE 
	C.NAME IN
	(
        SELECT 
        O.NAME
        FROM 
        ORDERS O,
        PART P
 	    WHERE 
        O.PARTNUM = P.PARTNUM
		AND
		O.QUANTITY * P.PRICE > 
        (
            SELECT 
            AVG(O.QUANTITY * P.PRICE)
 		   FROM 
            ORDERS O,
            PART P
 		   WHERE 
            O.PARTNUM = P.PARTNUM
        )
    )
	
注:在子查询中使用关键字 IN 是非常普遍的,
   因为 IN 可以与一组数据进行对比,
   而且它不会使 SQL 的引擎
   检查出其中有冲突或是不合适的地方。



2. 子查询也可以使用 GROUP BYHAVING 子句
    SELECT
    NAME,
    AVG(QUANTITY)
    FROM ORDERS
	GROUP BY NAME
    HAVING 
    AVG(QUANTITY) > 
    (
        SELECT AVG(QUANTITY)
		FROM ORDERS
    )
	

5. 相关子查询

相关子查询可以接受外部的引用:
	
	SELECT
    * 
    FROM 
    ORDERS O 
    WHERE 'ROAD BIKE' =
(
    SELECT 
    DESCRIPTION 
    FROM PART P
	WHERE
    P.PARTNUM = O.PARTNUM
)


SELECT 
O.ORDEREDON,
O.NAME,
O.PARTNUM, 
O.QUANTITY, 
O.REMARKS
FROM 
ORDERS O 
PART P 
WHERE 
P.PARTNUM = O.PARTNUM
AND 
P.DESCRIPTION = 'ROAD BIKE';


注:
当在相关查询中使用 GROUP BYHAVING 子句时,HAVING 子句中的列必须
在 SELECTGROUP BY 子句中存在,
否则你将会收到一行非法引用的信息,
因为这时与子查询对应的是每一组而不是每一行,
对于组你无法进行比较操作.

6. 在子查询中使用EXIST,ANY和ALL关键字

EXISTS 、ANY 和 ALL 关键字的用法不像它看上去那么直观,如果子查询返回的内容为非空时,EXISTS 返回 TRUE 否则返回 FALSE 。


SELECT 
NAME,
ORDEREDON 
FROM ORDERS
WHERE EXISTS


用法扩展:
你可以使用 EXIST 来检查查询
是否确实存在输出,
从而实现对查询确实有结果才输出的控制,
如果你在相关查询中使用 EXISTS 关键字,
它将会检查你所指出的每一种情况.

SELECT 
NAME,
ORDEREDON 
FROM 
ORDERS O 
WHERE EXISTS
(
    SELECT * FROM 
    CUSTOMER C 
    WHERE 
    STATE ='NE' 
    AND 
    C.NAME = O.NAME
)

SELECT 
NAME,
ORDEREDON 
FROM 
ORDERS 
WHERE 
NAME = ANY
(
    SELECT 
    NAME 
    FROM 
    ORDERS 
    WHERE 
    NAME ='TRUE WHEEL'
)

注:
ANY 与子查询中的每一行与主查询进行比较,
并对子查询中的每一行返回一个 true
上例中
将 ANYSOME 替换
将会得到同样的结果.IN 的异同
相同结果:
SELECT 
NAME,
ORDEREDON 
FROM 
ORDERS 
WHERE 
NAME IN
(
    SELECT 
    NAME 
    FROM 
    ORDERS 
    WHERE 
    NAME ='TRUE WHEEL'
)

区别:
IN 没有如下写法:
SELECT 
NAME,
ORDEREDON 
FROM 
ORDERS 
WHERE 
NAME > ANY
(
    SELECT 
    NAME 
    FROM 
    ORDERS 
    WHERE 
    NAME = 'JACKS BIKE'
)

IN 只相当于多个等号的作用,ANYSOME 
则可以使用其它的比较运算符
如大于或小于,
它是你的一个新增工具.

SELECT 
NAME 
ORDEREDON,
FROM 
ORDERS 
WHERE 
NAME <> ALL
(
    SELECT 
    NAME 
    FROM 
    ORDERS
    WHERE 
    NAME = 'JACKS BIKE'
)



以上是关于5. SQL子查询—内嵌的SQL子句的主要内容,如果未能解决你的问题,请参考以下文章

带有“exists”子句和多个表的 SQL 子查询

SQL Fundamentals: 子查询 || 分析函数

Oracle - 子查询TOP - N

SQL Fundamentals: 子查询 || 行列转换(PIVOT,UNPIVOT,DECODE),设置数据层次(LEVEL...CONNECT BY)

WHERE 子句中的 SQL 查询子选择优化 (SQL Server)

sql 带有FROM子句的子查询