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语句的复杂。


相关文章
|
3月前
|
SQL 存储 开发框架
2、SQL查询-简单查询
2、SQL查询-简单查询
24 0
|
3月前
|
SQL 关系型数据库 MySQL
3、SQL查询-复杂查询
3、SQL查询-复杂查询
59 0
|
5月前
|
NoSQL MongoDB 数据库
查询数据
查询数据
41 4
|
SQL Oracle 关系型数据库
Oracle简单查询、条件查询、枚举查询、模糊查询、排序查询、函数查询等
Oracle简单查询、条件查询、枚举查询、模糊查询、排序查询、函数查询等
340 0
Oracle简单查询、条件查询、枚举查询、模糊查询、排序查询、函数查询等
|
缓存 自然语言处理 网络架构
Elasticearch 查询详解 (二)
elk官网: [https://www.elastic.co/guide/en/enterprise-search-clients/index.html](https://www.elastic.co/guide/en/enterprise-search-clients/index.html) 作者主页:https://www.couragesteak.com/
Elasticearch 查询详解 (二)
|
C++
202009-1称检测点查询
202009-1称检测点查询
79 0
202009-1称检测点查询
小技巧 - 如何查询医保卡号?
小技巧 - 如何查询医保卡号?
1522 0
小技巧 - 如何查询医保卡号?
|
SQL 关系型数据库 MySQL
五、简单查询
五、简单查询
144 0
|
SQL
【查询】查询好像也可以很简单!
     还是要先说一下范围:以数据库为主的程序,b/s结构。        查询嘛,对于我来说就是SQL语句 where 后面(group、order by 前面的)的内容,把这搞定了,查询也就搞定了。
837 0
|
JavaScript 索引
查询
find简介 MonngoDB中使用find来进行查询。查询就是返回集合文档中的子集,子集的范围从0个到文档到整个集合。find的第一个参数决定了要返回哪些文档,这个参数是一个文档,用于指定的查询条件。
878 0

相关课程

更多