【T-SQL基础】03.子查询

本系列【T-SQL基础】主要是针对T-SQL基础的总结。

【T-SQL基础】01.单表查询-几道sql查询题

【T-SQL基础】02.联接查询

【T-SQL基础】03.子查询

【T-SQL基础】04.表表达式

【T-SQL基础】05.集合运算

【T-SQL基础】06.透视、逆透视、分组集

【T-SQL基础】07.数据修改

【T-SQL基础】08.事务和并发

【T-SQL基础】09.可编程对象

----------------------------------------------------------

【T-SQL性能调优】01.索引优化

【T-SQL性能调优】02.执行计划

【T-SQL性能调优】03.死锁分析

练习题:

1.写一条查询语句,返回Orders表中活动的最后一天生成的所有订单。

2.查询出拥有订单数量的最多的客户下过的所有订单。

3.查询出2008年5月1号(包括这一天)以后没有处理过订单的雇员。

4.查询2007年下过订单,而在2008年没有下过订单的客户

5.查询定购了第12号产品的客户

概述:

本篇主要是子查询基础的总结。

关键词解释:

外部查询:查询结果集返回给调用者

内部查询:查询结果集返回给外部查询。

独立子查询:独立子查询独立于其外部查询的子查询,可以单独运行子查询。在逻辑上,独立子查询在执行外部查询之前先执行一次,接着外部查询再使用子查询的结果继续进行查询。

相关子查询:引用了外部查询中出现的表的子查询,查询要依赖于外部查询,不能独立地调用它。在逻辑上,子查询会为每个外部行单独计算一次。

标量子查询:返回单个值的子查询。标量子查询可以出现在外部查询中期望使用单个值的任何地方。

多值子查询:在一个列中

为什么要使用子查询?

可以避免在查询解决方案中把操作分成多个步骤,并在变量中保存中间查询结果的需要。

一、独立子查询

1.独立标量子查询(查看练习题1,2)

例子:从HR.Employees表中返回empid最大的员工信息。

可以分两步:

a.定义一个变量maxid ,通过独立标量子查询查询出empid最大的员工的empid,然后将这个empid保存到变量@maxid中

b.在WHERE条件中过滤出empid = @maxid的记录

DECLARE @maxid AS INT = ( SELECT    MAX(empid)
                          FROM      HR.Employees
                        )
SELECT  *
FROM    HR.Employees
WHERE   empid = @maxid  

更简单的方法是嵌套子查询,只需要一条查询语句就可以查询出empid最大的员工信息

SELECT  *
FROM    HR.Employees
WHERE   empid = ( SELECT    MAX(empid)
                  FROM      HR.Employees
                )

注意:

1.对于有效的标量子查询,它的返回值不能超过一个,如果标量子查询返回了多个值,在运行时则可能会失败。

2.如果标量子查询没有返回任何值,其结果就转换为NULL,和NULL行进行比较得到的是UNKNOWN,查询过滤器不会返回任何让过滤表达式计算结果为UNKNOWN的行。

2.独立多值子查询(查看练习题3)

(1)多值子查询的语法格式

<标量表达式> IN ( <多值子查询> )

例子:返回title包含manager的雇员处理过的订单的信息

方案一:独立多值子查询

SELECT  *
FROM    Sales.Orders
WHERE   empid IN ( SELECT   empid
                   FROM     HR.Employees
                   WHERE    HR.Employees.title LIKE ‘%Manager‘ )

方案二:内联接查询

SELECT  *
FROM    Sales.Orders
        INNER JOIN HR.Employees ON Sales.Orders.empid = HR.Employees.empid
WHERE   HR.Employees.title LIKE ‘%Manager‘

类似地,很多地方既可以用子查询也可以用联接查询来解决问题。数据库引擎对两种查询的解释有时候是一样的,而在另外一些情况下,对二者的解释则是不同的。可以先用一种查询解决问题,如果性能不行,再尝试用联接替代子查询,或用子查询替代联接。

3.子查询之distinct关键字

当我们想要剔除掉子查询中的重复值时,会想到在子查询中不必指定distinct关键字,其实是没有必要的,因为数据库引擎会帮助我们删除重复的值,而不用我们显示指定distinct关键字。

二、相关子查询

1.相关子查询

什么是相关子查询:引用了外部查询中出现的表的列,依赖于外部查询,不能独立地运行子查询。在逻辑上,子查询会为每个外部行单独计算一次。

例子:查询每个客户返回在他参与活动的最后一天下过的所有订单。

期望结果:

影响行数:90

1.首先用独立标量子查询查询出最大的订单日期,返回给外部查询

SELECT  MAX(orderdate)
FROM    sales.Orders AS O2

2.外部查询用O1.orderdate进行过滤,过滤出等于最大订单日期的订单

3.因为要查询出每个客户参与的订单,所以将独立标量子查询改成相关子查询,用子查询O2.custid与外查询O1.custid关联。

对于O1中每一行,子查询负责返回当前客户的最大订单日期。如果O1中某行的订单日期和子查询返回的订单日期匹配,那么O1中的这个订单日期就是当前客户的最大的订单日期,在这种情况下,查询便会返回O1表中的这个行。

SELECT  MAX(orderdate)
FROM    sales.Orders AS O2
WHERE   O2.custid = O1.custid

综合上面的步骤,得到下面的查询语句:

SELECT  orderid,orderdate,custid
FROM    sales.Orders AS O1
WHERE   O1.orderdate = ( SELECT MAX(orderdate)
                         FROM   sales.Orders AS O2
                         WHERE  O2.custid = O1.custid
                       )

2.EXISTS谓词(查看练习题4,5)

  1. <外查询>  WHERE EXISTS ( 子查询 )
  2. 它的输入是一个子查询,:如果子查询能够返回任何行,改谓词则返回TRUE,否则返回FALSE.
  3. 如果子查询查询结果又多条,SQL SERVER引擎查询出一条记录后,就会立即返回,这种处理方式叫做短路处理。
  4. Exist谓词只关心是否存在匹配行,而不考虑SELECT列表中指定的列,所有使用SELECT * FROM TABLE,并没有什么负面影响,但是为了展开*代码的列名会有少少量的开销,但是还是推荐使用*通配符,查询语句应该尽可能保持自然和直观,除非有非常令人信服的理由,才可以牺牲代码在这方面的要求。
  5. NOT EXISTS谓词是EXISTS谓词的反面

三、练习题

1.写一条查询语句,返回Orders表中活动的最后一天生成的所有订单。

期望结果:

本题考察独立子查询的基本用法,首先用独立子查询返回最后一天的日期,然后外部查询过滤出订单日期等于最后一天的所有订单。

SELECT  orderid ,
        orderdate ,
        custid ,
        empid
FROM    Sales.Orders
WHERE   orderdate = ( SELECT    MAX(orderdate)
                      FROM      Sales.Orders

                    )

2.查询出拥有订单数量的最多的客户下过的所有订单。

期望结果:

本题考察独立子查询的用法,和第一题类似,分两个步骤:

(1)先用子查询查询出订单数量最多的客户id

(2)然后将id返回给外部查询,外部查询通过客户id过滤出客户下过的所有订单

方案一:独立标量子查询

SELECT  custid ,
        orderid ,
        orderdate ,
        empid
FROM    Sales.Orders
WHERE   custid = ( SELECT TOP ( 1 ) WITH TIES
                            O.custid
                   FROM     Sales.Orders AS O
                   GROUP BY custid
                   ORDER BY COUNT(*) DESC

                 )

注意:

TOP ( 1 ) WITH TIES O.custid

查找出排序后与第一条记录O.custid相等的所有行

因为下过订单数最多的客户的总订单数是31,且只有一个客户(custid=71),所以最后的查询结果中只有custid=71的客户下过的所有订单。

3.查询出2008年5月1号(包括这一天)以后没有处理过订单的雇员。

期望结果:

本题考察独立子查询的用法,本题也可以采用两步来查询出结果。

(1)首先用子查询返回所有2008年5月1号(包括这一天)以后处理过订单的雇员,将这些雇员的empid返回给外部查询

(2)然后外部查询用NOT IN过滤出所有2008年5月1号(包括这一天)之后没有处理过订单的雇员

方案一:独立标量子查询 + NOT IN

SELECT  *
FROM    HR.Employees
WHERE   empid NOT IN ( SELECT   empid
                       FROM     Sales.Orders
                       WHERE    orderdate >= ‘20080501‘ )

4.查询2007年下过订单,而在2008年没有下过订单的客户

期望输出:

方案一:内联接+独立标量子查询

1.查询出20070101~20071231所有下过订单的客户集合Collection1

SELECT DISTINCT C.custid,companyname FROM Sales.Orders O
	INNER JOIN Sales.Customers AS C ON C.custid = O.custid
	WHERE (orderdate <= ‘20071231‘ AND orderdate >= ‘20070101‘)

2.查询出20080101~20081231所有下过订单的客户结合Collection2

SELECT C.custid FROM Sales.Orders O
	INNER JOIN Sales.Customers AS C ON C.custid = O.custid
	WHERE (orderdate <= ‘20081231‘ AND orderdate >= ‘20080101‘)

3.Collection1不包含Collection2的子集就是2007年下过订单而在2008年下过订单的客户

SELECT DISTINCT C.custid,companyname FROM Sales.Orders O
	INNER JOIN Sales.Customers AS C ON C.custid = O.custid
	WHERE (orderdate <= ‘20071231‘ AND orderdate >= ‘20070101‘)
	AND C.custid NOT IN
(
	SELECT C.custid FROM Sales.Orders O
	INNER JOIN Sales.Customers AS C ON C.custid = O.custid
	WHERE (orderdate <= ‘20081231‘ AND orderdate >= ‘20080101‘)
)

方案二:相关子查询 EXISTS+NOT EXISTS

1.查询出20070101~20071231所有下过订单的客户集合Collection1

2.查询出20080101~20081231所有下过订单的客户结合Collection2

3.Collection1不包含Collection2的子集就是2007年下过订单而在2008年下过订单的客户

SELECT  C.custid ,
        companyname
FROM    Sales.Customers AS C
WHERE   EXISTS ( SELECT *
                 FROM   Sales.Orders AS O
                 WHERE  O.custid = C.custid
                        AND ( orderdate <= ‘20071231‘
                              AND orderdate >= ‘20070101‘
                            ) )
        AND NOT EXISTS ( SELECT *
                         FROM   Sales.Orders AS O
                         WHERE  O.custid = C.custid
                                AND ( orderdate <= ‘20081231‘
                                      AND orderdate >= ‘20080101‘
                                    ) )    

 

由方案一和方案二,我们可以总结出:INNER JOIN+独立子查询可以用Exists+相关子查询代替

5.查询订购了第12号产品的客户

期望结果:

方案一:内联接多张表

SELECT DISTINCT
        C.custid ,
        companyname
FROM    Sales.Customers AS C
        INNER JOIN Sales.Orders AS O ON C.custid = O.custid
        INNER JOIN Sales.OrderDetails AS D ON O.orderid = D.orderid
WHERE   D.productid = ‘12‘

方案二:嵌套相关子查询

SELECT  C.custid ,
        companyname
FROM    Sales.Customers AS C
WHERE   EXISTS ( SELECT *
                 FROM   Sales.Orders AS O
                 WHERE  O.custid = C.custid
                        AND EXISTS ( SELECT *
                                     FROM   Sales.OrderDetails AS D
                                     WHERE  D.orderid = O.orderid
                                            AND D.productid = ‘12‘ ) )
时间: 2024-12-14 12:19:23

【T-SQL基础】03.子查询的相关文章

SQL 基础之子查询(十一)

子查询:类型.语法.和注意事项 使用子查询能解决哪些问题? 子查询语法: select select_list from table where expr operator (select select_list from table); 子查询(内查询)在主查询(外查询)之前执行. 主查询使用子查询结果. 位置:select,where,from,having 1.查询谁的工资比Abel高 select last_name, salary from employees where salary

SQL 基础之子查询、多表插入、merge 语句、跟踪一段时间数据变化(二十)

使用子查询处理数据 可以使用子查询中的数据操纵语言(DML)语句: 使用内嵌视图检索数据 从一张表向另一张表复制数据 基于另一张表的值更新表中数据 基于另一张表的值删除表中的行 使用子查询作为数据源检索数据 select department_name, city from departments natural join (select l.location_id, l.city, l.country_id from loc l join countries c on(l.country_id

SQL基础--&amp;gt;层次化查询(START BY ... CONNECT BY PRIOR)

--====================================================== --SQL基础-->层次化查询(START BY ... CONNECT BY PRIOR) --====================================================== 层次化查询,即树型结构查询,是SQL中经经常使用到的功能之中的一个,通常由根节点,父节点,子节点,叶节点组成,其语法例如以下: SELECT [LEVEL] ,column,ex

sql example 9 -- 子查询

sql example 9 – 子查询 sql example 9 – 子查询 数据库准备 create table student ( id int auto_increment primary key, name varchar(10) ); create table scores ( id int auto_increment PRIMARY key, score int default 0, foreign key (id) references student(id) on delet

MYSQL基础九--子查询和连接

1.子查询是出现在其他SQL语句内的SELECT子句. 子查询指嵌套在查询内部,且必须始终出现在圆括号内. 子查询可以包含多个关键字或条件,如DISTINCT,GROUP BY,ORDER BY,LIMIT,函数等. 子查询的外层查询可以是:SELECT,UPDATE,INSERT,SET或DO. 2.子查询的返回结果 子查询可以返回标量,一行,一列或子查询. 3.使用比较运算符的子查询 SELECT goods_id,goods_name,goods_price FROM tab_red WH

数据库基础(子查询、设置主键外键)

子查询,又叫做嵌套查询. 将一个查询语句做为一个结果集供其他SQL语句使用,就像使用普通的表一样,被当作结果集的查询语句被称为子查询. 子查询有两种类型: 一种是只返回一个单值的子查询,这时它可以用在一个单值可以使用的地方,这时子查询可以看作是一个拥有返回值的函数: 另外一种是返回一列值的子查询,这时子查询可以看作是一个在内存中临时存在的数据表. 子查询示例: 练习一: 练习二: 练习三: 分页查询语句示例: 查看总共可以分为多少页: 主键        数据库主键是指表中一个列或列的组合,其值

SQL练习 高级子查询

• 书写多列子查询• 在 FROM 子句中使用子查询• 在SQL中使用单列子查询• 书写相关子查询• 使用 EXISTS 和 NOT EXISTS 操作符• 使用子查询更新和删除数据• 使用 WITH 子句 --多列子查询(不成对比较 & 成对比较)1. 查询与141号或174号员工的manager_id和department_id相同的其他员工的employee_id, manager_id, department_id [方式一]SELECT employee_id, manager_id,

在SQL Server的子查询、视图、内联函数等数据库对象中,不应该单独使用ORDER BY语句

我们知道在SQL语句中,ORDER BY语句可以用来排序.但是在SQL Server中,如果我们在子查询.视图.内联函数等数据库对象中单独使用ORDER BY语句是不允许的,来看下面的SQL语句: SELECT * FROM ( SELECT [ID],[Code],[Name],[Age],[Sex],[Class] FROM [dbo].[Student] ORDER BY [ID] DESC ) AS T_Student 执行该语句,SQL Server会报错,错误信息如下: The OR

SQL里的子查询

子查询必须遵守的规则 子查询必须位于圆括号内. 除非子查询里有多个字段让子查询进行比较,否则子查询的SELECT子句里只能有一个字段. 子查询里不能使用ORDER BY子句.在子查询里,我们可以利用GROUP BY子句实现ORDER BY功能. 返回多条记录的子查询只能与多值操作符(比如IN)配合使用. SELECT列表里不能引用任何BLOB.ARRAY.CLOB或NCLOB类型的值. 子查询不能直接被包围在函数里 操作符BETWEEN不能用于子查询,但子查询内部可以使用它. SELECT CO