6. 复杂查询

简介: 6. 复杂查询

编写子查询

sql

复制代码

use sql_store;
-- Find products that are more
-- expensive than Lettuce ( id = 3)
-- 编写子查询
select *
from products
where name like 'Lettuce%';
    
select *
from products
where unit_price > (
  select unit_price
  from products
  where name like 'Lettuce%'
)

sql

复制代码

-- In sql_hr database:
-- Find employees whose earn more than average
use sql_hr;
select 
  avg(salary) as avergae
from employees;
-- 没有结果
select *
from employees
having salary > avg(salary);
-- 正确答案
select *
from employees
where salary > (
  select 
  avg(salary)
  from employees
  )

注意:having 中不可以再使用属性名比较,只能使用聚合函数判断;同样的道理,where 反过来

需要确定子查询是返回的唯一值才可以继续,如果一个集合,可以考虑用 in

in运算符

sql

复制代码

use sql_store;
-- Find the products that have never been ordered
select *
from products
where product_id not in (
  select 
    distinct product_id
  from order_items
)

使用 in 运算符,进行子查询。

sql

复制代码

use sql_invoicing;
select *
from clients
where client_id not in(
  select distinct client_id
    from invoices
)

子查询和连接

子查询(Subquery)是将一张表的查询结果作为另一张表的查询依据并层层嵌套,其实也可以先将这些表链接(Join)合并成一个包含所需全部信息的详情表再直接在详情表里筛选查询。 两种方法一般是可互换的,具体用哪一种取决于 效率/性能(Performance) 和 可读性(readability)

sql

复制代码

select *
from clients
where client_id not in(
  select distinct client_id
    from invoices
);
select *
from clients
left join invoices using (client_id)
where invoice_id is NULL;

sql

复制代码

use sql_store;
select 
  customer_id, 
    first_name,
    last_name
from customers c
where c.customer_id in (
  select customer_id
    from orders o
    where o.order_id in (
    select order_id
    from order_items oi
    where oi.product_id = (
      select product_id
      from products p
      where p.name like 'Lettuce%'
    )
    )
)
-- 上面是使用嵌套的方法,同样可以写出连接的方法,这里就不写了

这个案例中,先将所需信息所在的几张表全部连接合并成一张大表再来查询筛选明显比层层嵌套的多重子查询更加清晰明了

all关键字

sql

复制代码

use sql_invoicing;
select *
from invoices
where invoice_total > (
  select max(invoice_total)
  from invoices 
  where client_id = 3
);
select *
from invoices
where invoice_total > ALL (
  select invoice_total
  from invoices 
  where client_id = 3
);

上面的子查询返回了一列值 使用ALL会和子查询里面返回的所有值进行比较,父查询如果存在满足所有子查询条件,返回这条记录。 等价于在子查询中 max()

any关键字

sql

复制代码

select *
from clients
where client_id in(
  select client_id
  from invoices
  group by client_id
  having count(*) >= 2
);
select *
from clients
where client_id = any(
  select client_id
  from invoices
  group by client_id
  having count(*) >= 2
);

如果说 all 是与运算,那么 any 就是或运算 = any等价于in

ANY/SOME (……) 与 > (MIN (……)) 等效

  • = ANY/SOME (……) 与 IN (……) 等效

相关子查询

sql

复制代码

-- Select employees whose salary is
-- above the average in their office
use sql_hr;
select *
from employees e
where salary > (
  select avg(salary)
    from employees
    where office_id = e.office_id
)

如上面样例中的类似,如果在子查询中出现了父查询表的别名,就可以称为相关子查询。 没有则是不相关子查询

注意:使用相关子查询,这段查询会在主查询的每一行的层面执行,所以相关子查询会很慢

sql

复制代码

-- Get invoices that are larger than the
-- client's average invoice amount
use sql_invoicing;
select *
from invoices i
where invoice_total > (
  select
    avg(invoice_total) as average
  from invoices
    where client_id = i.client_id
);

exists 运算符

IN + 子查询 等效于 EXIST + 相关子查询如果前者子查询的结果集过大占用内存,用后者逐条验证更有效率。 另外 EXIST() 本质上是根据是否为空返回 TRUE 和 FALSE,所以也可以加 NOT 取反。

sql

复制代码

-- Select clients that have an invoice
select *
from clients
where client_id in (    -- in (1, 2, 3, 5)
  select distinct client_id
    from invoices
);
-- 使用exist
select *
from clients c
where exists (
  select client_id
    from invoices
    where client_id = c.client_id
)

**注意: 上面这个代码先执行子查询 in ( ),并把查询结果返回到 where 子句。 如果返回的结果非常多,会妨碍最佳性能

使用 exists 可以优化这个查询中的性能 子查询并没有真的把结果集返回给外查询**

sql

复制代码

-- Find the products that have never been ordered
use sql_store;
select *
from products p
where not exists(
  select *
    from order_items
    where product_id = p.product_id
)

只写 select * 就可以了,不需要选具体的属性。

select子句中的子查询

sql

复制代码

select
  invoice_id,
    invoice_total,
    (select avg(invoice_total)
    from invoices) as invoice_average,
  invoice_total - (select invoice_average) as difference
from invoices

简单讲就是,SELECT选择语句是用来确定查询结果选择包含哪些字段 每个字段都可以是一个表达式,而每个字段表达式里的元素除了可以是原始的列,具体的数值,也同样可以是其它各种花里胡哨的子查询的结果

sql

复制代码

select
  client_id,
    c.name,
    (select sum(invoice_total)
    from invoices i
        where i.client_id = c.client_id) as total_sales,
  (select avg(invoice_total)
    from invoices i) as average,
  (select total_sales) - (select average) as difference 
from clients c;

很多奇特的用法:

  • (select total_sales) - (select average) as difference 这句可以直接写为(select total_sales - average) 可以理解为两个子查询在同一张表里面,可以直接减掉。
  • 子查询的使用了相关子查询,没有使用join连接,更优。原理可以看上面的相关子查询。

from子句中的子查询

sql

复制代码

USE sql_invoicing;
select *
from (
  -- 每当我们在form子句中使用子查询,必须要给子查询的结果一个别名
  select
    client_id,
    c.name,
    (select sum(invoice_total)
      from invoices i
      where i.client_id = c.client_id) as total_sales,
    (select avg(invoice_total)
      from invoices i) as average,
    (select total_sales) - (select average) as difference 
  from clients c
) as sales_summary
where total_sales is not null

很好理解,子查询当成一张表再次查询。 需要注意的是,每当我们在form子句中使用子查询,必须要给子查询的结果一个别名

from中的子查询会让查询变得复杂,但是可以使用视图(views)来存储这张表,可以大大简化sql语句的复杂。


相关文章
|
缓存 NoSQL Shell
MongoDB系列-在复制集(replication)以及分片(Shard)中创建索引
在使用MongoDB时,在创建索引会涉及到在复制集(replication)以及分片(Shard)中创建,为了最大限度地减少构建索引的影响,在副本和分片中创建索引,使用滚动索引构建过程。
669 0
|
11月前
|
数据采集 人工智能 自然语言处理
文档智能 & RAG让AI大模型更懂业务
《文档智能 & RAG让AI大模型更懂业务》解决方案基于文档智能技术和检索增强生成(RAG)方法,通过结构化企业内部文档并结合实时检索,显著提升了大模型对业务内容的理解能力。方案在金融、法律、医疗等行业的应用表现出色,但在大规模文档管理和个性化定制方面仍有改进空间。部署文档详细但需增加更多排错指导。
|
11月前
|
缓存 JavaScript 前端开发
qiankun 微应用vue接入到基座
【10月更文挑战第4天】
|
10月前
|
数据管理 大数据 OLAP
AnalyticDB核心概念详解:表、索引与分区
【10月更文挑战第25天】在大数据时代,高效的数据库管理和分析工具变得尤为重要。阿里云的AnalyticDB(ADB)是一款完全托管的实时数据仓库服务,能够支持PB级数据的实时查询和分析。作为一名数据工程师,我有幸在多个项目中使用过AnalyticDB,并积累了丰富的实践经验。本文将从我个人的角度出发,详细介绍AnalyticDB的核心概念,包括表结构设计、索引类型选择和分区策略,帮助读者更有效地组织和管理数据。
453 3
|
SQL Cloud Native 关系型数据库
云原生数据仓库使用问题之分组优化如何实现
阿里云AnalyticDB提供了全面的数据导入、查询分析、数据管理、运维监控等功能,并通过扩展功能支持与AI平台集成、跨地域复制与联邦查询等高级应用场景,为企业构建实时、高效、可扩展的数据仓库解决方案。以下是对AnalyticDB产品使用合集的概述,包括数据导入、查询分析、数据管理、运维监控、扩展功能等方面。
|
存储 SQL Java
技术心得:压缩包Zip格式详析(全网最详细)
技术心得:压缩包Zip格式详析(全网最详细)
1100 0
|
SQL 设计模式 安全
Java单例模式几种写法以及代码案例拿来直接使用
Java单例模式几种写法以及代码案例拿来直接使用
100 0
|
SQL XML 存储
Flowable 任务如何认领,回退?
Flowable 任务如何认领,回退?
|
自然语言处理 算法 程序员
【C语言技能树】程序环境和预处理
在ANSI C的任何一种实现中,存在两个不同的环境。
181 0
|
存储 算法 区块链
GRETT格莱特智能合约系统开发|格莱特质押模式系统开发DAPP技术搭建
“去中心化”是区块链的典型特征之一 The liquidity providers provide the pool with the two