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 BY 和 HAVING 子句
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 BY
和 HAVING 子句时,
在 HAVING 子句中的列必须
在 SELECT 或 GROUP 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
上例中
将 ANY 用 SOME 替换
将会得到同样的结果.
与 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 只相当于多个等号的作用,
而 ANY 和 SOME
则可以使用其它的比较运算符
如大于或小于,
它是你的一个新增工具.
SELECT
NAME
ORDEREDON,
FROM
ORDERS
WHERE
NAME <> ALL
(
SELECT
NAME
FROM
ORDERS
WHERE
NAME = 'JACKS BIKE'
)
以上是关于5. SQL子查询—内嵌的SQL子句的主要内容,如果未能解决你的问题,请参考以下文章
SQL Fundamentals: 子查询 || 行列转换(PIVOT,UNPIVOT,DECODE),设置数据层次(LEVEL...CONNECT BY)