【MySQL】子查询

文章目录

子查询

  • 获取价格大于id为3的货物的商品
    • 用到了内查询,获取id为3的商品的单价,把结构传给外查询
  • 在where子句中编写子查询,也可以在from或select子句中编写。
sql 复制代码
use sql_store;
select *
from products
where unit_price > (
    select unit_price
    from products
    where product_id = 3
    )

运行结果:

  • 练习:查询工资大于平均工资的员工
sql 复制代码
use sql_hr;
select *
from employees
where salary > (
    select avg(salary)
    from employees
    )

运行结果:

IN运算符

  • in运算符写子查询
  • 查询没有被订购过的商品,先在子查询中找出被订购过的商品id(注意要去重)。将这个查询结果作为子查询,在外层找product_id不在子查询结果里的数据,就是没有被订购过的商品。
sql 复制代码
use sql_store;
select *
from products
where product_id not in (
    select distinct product_id
    from order_items
)
  • 练习:找到没有支付过支票的客户
    • 从invoices中查询去重后的clientid,将这个结果作为内查询传给外查询,找不在这个内查询结果中的id,就是没有支付过支票的顾客
sql 复制代码
use sql_invoicing;
select *
from clients
where client_id not in (
    select distinct client_id
    from invoices
)

运行结果:

子查询 VS 连接

  • 在运行时间差不多的情况下,应该选择最易读的查询,要注意代码的可读性!
  • 上一个练习题,可以使用外连接进行查询,但这样写可读性不好。
sql 复制代码
select *
from clients
left join invoices using (client_id)
where invoice_id is null
  • 练习
    • 找到订购了货物id为3的顾客
    • 这道题用 连接查询 思路更清晰,可读性更好
sql 复制代码
-- 用子查询写
use sql_store;
select customer_id, first_name, last_name
from customers
where customer_id in (
    select customer_id
    from order_items
    join orders using (order_id)
    where product_id = 3
)

-- 使用连接查询
select distinct customer_id, first_name, last_name
from customers
join orders using (customer_id)
join order_items using (order_id)
where product_id = 3

ALL关键字

  • 查询大于3号客户的最大发票的所有数据
sql 复制代码
use sql_invoicing;
select *
from invoices
where invoice_total > (
    select max(invoice_total)
    from invoices
    where client_id = 3
    )
  • 用all关键字
    • 查询invoice_total比all后查询到的所有数据都大的数据,一个一个的跟all后查询到的结果进行比较
sql 复制代码
select *
from invoices
where invoice_total > all(
    select invoice_total
    from invoices
    where client_id = 3
    )

返回结果

  • max写法和all写法可以相互改写,两种写法的可读性都较好

ANY关键字

  • in 和 = any是等价的。
  • 查询至少有两张发票的客户id
    • 使用count(*)查到所有的信息,根据client_id分组,分组后用having进行条件筛选
sql 复制代码
select client_id, count(*)
from invoices
group by client_id
having count(*) >= 2
  • 把上述查询当子查询,把clients中至少有两张发票的客户信息查出来
    • where子句中可以用in,也可以用 = any
    • in 和 = any的效果是一样的,用哪种都行
sql 复制代码
-- in
select *
from clients
where client_id in (
    select client_id
    from invoices
    group by client_id
    having count(*) >= 2
)
-- = any
select *
from clients
where client_id = any (
    select client_id
    from invoices
    group by client_id
    having count(*) >= 2
)

相关子查询 !

  • 查询逻辑:先到employees表,对每个员工e执行这段子查询,计算和e同一个部门的员工的平均工资,如果这名员工e的工资高于平均工资,就会被返回在结果中。依次一条一条的去查询。
  • 这种查询成为相关子查询,子查询和外查询存在相关性,引用了外查询里出现的别名(即e)
  • 使用相关子查询时,这段子查询会在主查询每一行的层面执行,所以相关子查询经常执行的很慢。
sql 复制代码
use sql_hr;
select *
from employees e
where salary > (
    select avg(salary)
    from employees
    where office_id = e.office_id
    )
  • 练习
    • 查询顾客大于自己平均值的数据
sql 复制代码
use sql_invoicing;
select *
from invoices i
where invoice_total > (
    select avg(invoice_total)
    from invoices
    where client_id = i.client_id
    )

EXISTS运算符

  • 获取在发票表中有发票的客户
    • 三种写法:子查询,外连接,exists相关子查询
  • 用in,先将in后的子查询运行结果返回给where。
  • in后的子查询会生成一个列表,返回给where。如果子查询查到的过多,会导致列表特别大,这样会妨碍最佳性能;对于这种情况,用exists能提高效率
sql 复制代码
select *
from clients
where client_id in (
    select distinct client_id
    from invoices
    )
  • 用exists运算符,来查看发票表里是否存在符合这个条件的行
  • 子查询并没有给外查询返回一个结果,它会返回一个指令,说明这个子查询中是否有符合这个搜索条件的行,每一行外层查询的数据都到exists后去看是否存在;如果存在,子查询就会给exists返回true,exists运算符就会在最终结果里添加当前的记录。
sql 复制代码
select *
from clients
where exists(
    select client_id
    from invoices
    where invoices.client_id = clients.client_id
);

运行结果

  • 练习
    • 找到从没有被订购过的商品
sql 复制代码
use sql_store;
select *
from products
where not exists(
    select product_id
    from order_items
    where order_items.product_id = products.product_id
)

运行结果

select子句中的子查询

  • 在select子句中用子查询得到平均值
  • select语句中 在表达式中不能使用列的别名,这样就只能把select子句中的子查询再复制一遍,但是这样很长很麻烦且重复;解决方法是:再转换成一个子查询(select invoice_average)
sql 复制代码
use sql_invoicing;
select invoice_id,
       invoice_total,
       (select avg(invoice_total)
            from invoices) as invoice_avearge,
       invoice_total - (select invoice_avearge) as difference
from invoices

运行结果

  • 练习:得到每个客户的总发票金额,全部发票的平均值,以及他们的差值
sql 复制代码
select client_id,
       name,
       (select sum(invoice_total)
        from invoices
        where client_id = c.client_id) as total_sales,
       (select avg(invoice_total)
        from invoices) as average,
       (select total_sales) - (select average) as difference
from clients c

运行结果

from子句中的子查询

  • 可以把一段查询生成的表当作另一个查询的from
sql 复制代码
select *
from(
select client_id,
       name,
       (select sum(invoice_total)
        from invoices
        where client_id = c.client_id) as total_sales,
       (select avg(invoice_total)
        from invoices) as average,
       (select total_sales) - (select average) as difference
from clients c
) as hahah
where total_sales is not null

运行结果

相关推荐
剩下了什么6 小时前
MySQL JSON_SET() 函数
数据库·mysql·json
山峰哥7 小时前
数据库工程与SQL调优——从索引策略到查询优化的深度实践
数据库·sql·性能优化·编辑器
较劲男子汉7 小时前
CANN Runtime零拷贝传输技术源码实战 彻底打通Host与Device的数据传输壁垒
运维·服务器·数据库·cann
java搬砖工-苤-初心不变7 小时前
MySQL 主从复制配置完全指南:从原理到实践
数据库·mysql
WangYaolove13149 小时前
基于python的在线水果销售系统(源码+文档)
python·mysql·django·毕业设计·源码
山岚的运维笔记9 小时前
SQL Server笔记 -- 第18章:Views
数据库·笔记·sql·microsoft·sqlserver
roman_日积跬步-终至千里10 小时前
【LangGraph4j】LangGraph4j 核心概念与图编排原理
java·服务器·数据库
汇智信科10 小时前
打破信息孤岛,重构企业效率:汇智信科企业信息系统一体化运营平台
数据库·重构
野犬寒鸦10 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法
霖霖总总10 小时前
[小技巧66]当自增主键耗尽:MySQL 主键溢出问题深度解析与雪花算法替代方案
mysql·算法