目录
子查询的相关概念:
子查询的分类:
角度1:
单行子查询:
单行比较操作符:
子查询的空值情况:
多行子查询:
多行比较操作符:
ANY和ALL的区别:
子查询为空值的情况:
角度2:
相关(或者关联)子查询:
非相关(或者非关联)子查询:
EXISTS和NOT EXISTS关键字:
EXISTS:
NOT EXISTS:
子查询的基本使用:
子查询作为计算字段:
子查询结果作为临时表:
子查询结果作为过滤条件:
举例:
结论:
子查询的相关概念:
子查询是指一个查询语句嵌套在另一个查询语句的内部的查询。SQL中子查询的使用大大增加了SELECT查询的能力,因为很多时候查询需要从结果集中获取数据,或者需要从同一个表中先计算得出一个数据结果,然后这个数据结果(可能是某一标量,也可能是某个集合)进行比较。
子查询的称谓规范:外查询(主查询)、内查询(子查询)。
子查询需要使用()包裹,可多层嵌套。通常先执行子查询,再将结果传递给外部查询。
子查询放在比较条件的右侧,提高可读性。
子查询的分类:
角度1:
按照内查询的结果返回一条还是多条记录,将子查询分为:
单行子查询:
返回一个结果给主查询进行使用。
单行比较操作符:
操作符 | 含义 |
= | 等于查询的数据 |
> | 大于查询的数据 |
>= | 大于等于查询的数据 |
小于等于查询的数据 | |
<> | 不等于查询的数据 |
子查询的空值情况:
子查询如果查询的结果为NULL,是不会进行报错的。外查询运用这个查询结果也是NULL值。
多行子查询:
返回多个结果给主查询进行使用。
多行比较操作符:
操作符 | 含义 |
IN | 等于列表中任意一个 |
ANY | 需要和单行比较操作符一起使用,和子查询返回的某一个值进行比较 |
ALL | 需要和单行比较操作符一起使用,和子查询返回的所有值进行比较 |
SOME | 实际上是ANY的别名,作用相同,一般常用ANY |
ANY和ALL的区别:
ANY:如果主查询中的值满足与子查询返回的任意一个值之间的比较条件,则条件为真。
ALL:如果主查询中的值满足与子查询返回的所有值之间的比较条件,则条件为真。
子查询为空值的情况:
内查询有一个NULL值的话,外查询的结果为NULL。
角度2:
按照内查询是否被多次执行,将子查询分为:
相关(或者关联)子查询:
子查询依赖外部查询的当前行数据,需结合外部查询逐步处理。
子查询需要执行多次,即采用循环的方式,先从外部查询开始,每次都传入子查询进行查询,然后将结果反馈给外部。
非相关(或者非关联)子查询:
子查询独立于外部查询执行,不引用外部查询的任何字段,可单独运行并返回固定结果集供外部查询使用。
子查询从数据表中查询了数据结果,如果这个数据结果只执行一次,然后这个数据结果作为主查询的条件进行执行。
EXISTS和NOT EXISTS关键字:
关联子查询通常会和EXISTS和NOT EXISTS关键字一起使用,用于检查子查询是否存在满足条件的行。
EXISTS和NOT EXISTS基于布尔逻辑判断数据的存在性而返回具体数据值。
EXISTS:
检查子查询是否返回至少一行记录。
SELECT ...
FROM 主表
WHERE EXISTS (子查询);
如果子查询中不存在满足条件的行:条件返回FALSE,继续在子查询中查找。
如果在子查询中存在满足条件的行:不在子查询中继续查找,条件返回TREU。
NOT EXISTS:
检查子查询是否没有返回任何记录。
如果子查询中无结果:返回TRUE,保留改行。
如果子查询中有结果:返回FALSE,丢弃该行。
SELECT ...
FROM 主表
WHERE NOT EXISTS (子查询);
子查询的基本使用:
子查询作为计算字段:
必须返回单值。
SELECT 字段名1,字段名2,...
FROM 表名
WHERE 字段名3 比较操作符 (SELECT 返回的字段名FROM 表名WHERE 条件(不含聚合函数条件)
);
SELECT 字段名1,(SELECT 返回的字段名FROM 表名WHERE 条件
)
FROM 表名
WHERE 条件;
子查询结果作为临时表:
必须指定别名。
SELECT 字段名1,字段名2,...
FROM 表名1 JOIN (SELECT 字段名FROM 表名WHERE 条件
) AS 别名
WHERE 条件;
子查询结果作为过滤条件:
SELECT 字段名1,字段名2,...
FROM 表名
WHERE 字段名 比较操作符 (SELECT 字段名,(聚合函数)FROM 表名[WHERE 条件(无聚合函数条件)]GROUP BY 非聚合函数字段名HAVING 条件(包含聚合函数条件)
);
举例:
牛客网SQL题目:
返回购买价格为 10 美元或以上产品的顾客列表_牛客题霸_牛客网
OrderItems表示订单商品表,含有字段订单号:order_num、订单价格:item_price;Orders表代表订单信息表,含有顾客id:cust_id和订单号:order_num
OrderItems表
order_num | item_price |
a1 | 10 |
a2 | 1 |
a2 | 1 |
a4 | 2 |
a5 | 5 |
a2 | 1 |
a7 | 7 |
Orders表
order_num | cust_id |
a1 | cust10 |
a2 | cust1 |
a2 | cust1 |
a4 | cust2 |
a5 | cust5 |
a2 | cust1 |
a7 | cust7 |
使用子查询,返回单个订单的购买价格为 10 美元或以上产品的顾客列表,结果无需排序。
【示例结果】返回顾客id cust_id
cust_id |
cust10 |
因为这里子查询返回的结果为多个,所以使用多行比较操作符IN。
SELECT Orders.cust_id
FROM Orders
WHERE Orders.order_num IN (SELECT OrderItems.order_numFROM OrderItemsWHERE OrderItems.item_price >=10
);
牛客网SQL题目:
确定哪些订单购买了 prod_id 为 BR01 的产品(一_牛客题霸_牛客网
表OrderItems代表订单商品信息表,prod_id为产品id;Orders表代表订单表有cust_id代表顾客id和订单日期order_date
OrderItems表
prod_id | order_num |
BR01 | a0001 |
BR01 | a0002 |
BR02 | a0003 |
BR02 | a0013 |
Orders表
order_num | cust_id | order_date |
a0001 | cust10 | 2022-01-01 00:00:00 |
a0002 | cust1 | 2022-01-01 00:01:00 |
a0003 | cust1 | 2022-01-02 00:00:00 |
a0013 | cust2 | 2022-01-01 00:20:00 |
编写 SQL 语句,使用子查询来确定哪些订单(在 OrderItems 中)购买了 prod_id 为 "BR01" 的产品,然后从 Orders 表中返回每个产品对应的顾客 ID(cust_id)和订单日期(order_date),按订购日期对结果进行升序排序。
【示例结果】返回顾客id cust_id和定单日期order_date。
cust_id | order_date |
cust10 | 2022-01-01 00:00:00 |
cust1 | 2022-01-01 00:01:00 |
SELECT Orders.cust_id,Orders.order_date
FROM Orders
WHERE Orders.order_num IN (SELECT OrderItems.order_numFROM OrderItemsWHERE OrderItems.prod_id = 'BR01'
)
ORDER BY Orders.order_date ASC;
牛客网SQL题目:
返回购买 prod_id 为 BR01 的产品的所有顾客的电_牛客题霸_牛客网
你想知道订购 BR01 产品的日期,有表OrderItems代表订单商品信息表,prod_id为产品id;Orders表代表订单表有cust_id代表顾客id和订单日期order_date;Customers表含有cust_email 顾客邮件和cust_id顾客id
OrderItems表
Orders表
Customers表代表顾客信息,cust_id为顾客id,cust_email为顾客email
返回购买 prod_id 为BR01 的产品的所有顾客的电子邮件(Customers 表中的 cust_email),结果无需排序。
提示:这涉及 SELECT 语句,最内层的从 OrderItems 表返回 order_num,中间的从 Customers 表返回 cust_id。
【示例结果】
返回顾客email cust_email
我们先通过Orders表格中的order_num和OrderItems表格中的order_num进行相关的连接,查询得到想要的prod_id为"BR01"的order_num值。然后再将结果反馈给Customers表来进行相关的查询。因为这里主要讲的是子查询,所以就使用的子查询嵌套来表示。
SELECT Customers.cust_email
FROM Customers
WHERE Customers.cust_id IN (SELECT Orders.cust_idFROM OrdersWHERE Orders.order_num IN (SELECT OrderItems.order_numFROM OrderItemsWHERE OrderItems.prod_id = 'BR01')
);
牛客网SQL题目:
从 Products 表中检索所有的产品名称以及对应的销售总_牛客题霸_牛客网
Products 表中检索所有的产品名称:prod_name、产品id:prod_id
prod_id | prod_name |
a0001 | egg |
a0002 | sockets |
a0013 | coffee |
a0003 | cola |
OrderItems代表订单商品表,订单产品:prod_id、售出数量:quantity
prod_id | quantity |
a0001 | 105 |
a0002 | 1100 |
a0002 | 200 |
a0013 | 1121 |
a0003 | 10 |
a0003 | 19 |
a0003 | 5 |
编写 SQL 语句,从 Products 表中检索所有的产品名称(prod_name),以及名为 quant_sold 的计算列,其中包含所售产品的总数(在 OrderItems 表上使用子查询和 SUM(quantity)检索)。
【示例结果】返回产品名称prod_name和产品售出数量总和
prod_name | quant_sold |
egg | 105 |
sockets | 1300 |
coffee | 1121 |
cola | 34 |
这里将子查询的结果作为一个临时表,必须需要对临时表进行起别名。先通过将Products表格和自身建立连接,得到想要的子查询结果集,然后再将OrderItems表格建立连接。即可得到想要的结果集。
SELECT Products.prod_name,NewOrderItems.quant_sold
FROM Products JOIN (SELECT OrderItems.prod_id,SUM(OrderItems.quantity) AS quant_soldFROM OrderItemsGROUP BY OrderItems.prod_id
) AS NewOrderItems
ON Products.prod_id = NewOrderItems.prod_id;
牛客网SQL题目:
返回每个顾客不同订单的总金额_牛客题霸_牛客网
我们需要一个顾客 ID 列表,其中包含他们已订购的总金额。
OrderItems表代表订单信息,OrderItems表有订单号:order_num和商品售出价格:item_price、商品数量:quantity。
Orders表订单号:order_num、顾客id:cust_id
编写 SQL语句,返回顾客 ID(Orders 表中的 cust_id),并使用子查询返回total_ordered 以便返回每个顾客的订单总金额,将结果按金额从大到小排序。
【示例结果】返回顾客id cust_id和total_order下单总额
因为要查询顾客ID所对应的订单总金额,所以通过OrderItems表格的自连接得到一个按照order_num分组并计算所对应的价格总和的临时表。通过Orders表格和OrderItems表格进行连接查询,得到想要的查询结果集。
SELECT的执行顺序:FROM在SELECT之前,并且子查询先执行,所以能够直接把NewOrderItems.total_ordered直接放在主查询SELECT后面。
因为子查询中含有聚合函数,所以子查询中的过滤条件应该使用HAVING关键字。
SELECT Orders.cust_id,NewOrderItems.total_ordered
FROM Orders JOIN (SELECT OrderItems.order_num,SUM(OrderItems.item_price*OrderItems.quantity) AS total_orderedFROM OrderItemsGROUP BY OrderItems.order_numORDER BY total_ordered DESC
) AS NewOrderItems
ON Orders.order_num = NewOrderItems.order_num;
结论:
在SELECT中,除了在GROUP BY和LIMIT之外,都能使用子查询。