在 SQL Server 数据库的 WHERE 语句中使用子查询

这是关于子查询语句的一系列文章中的第三篇。在这篇文章中我们将讨论WHERE语句中的子查询语句。其他的文章讨论了其他语句中的子查询语句。

本次课程中的所有例子都是基于Microsoft SQL Server Management Studio和AdventureWorks2012数据库的。读者可以阅读我的SQL Server使用入门学习使用这些免费的工具。

在WHERE语句中使用子查询

在WHERE语句中使用子查询是非常常见的。常见的用法是用EXISTS或IN测试存在性。在某些情况下重新考虑查询语句并且使用JOIN是有意义的,但是在最终决定之前,应该好好学习一下这两种通过查询优化的形式。

比较修饰符ANY和ALL可以和greater than,less than,或者equals操作符一起使用。这样就提供了一种方式比较一个单值,例如一个列,一个或更多的子查询返回的结果。

现在我们详细讨论这些。

芝麻开花节节矮
翻译于 2个月前

0人顶

 翻译的不错哦!

Exist和Not Exists

EXISTS条件结合子查询使用.当子查询返回一个或多个记录的时候,它返回TRUE.

EXISTS条件最简单的语法形式如下:

?


1

WHERE EXISTS (sub query)

假设我们需要返回,所有由销售人员记录的,从年初至今,大于三百万美元的销售订单.为了达到这个效果,我们可以使用如下例子中的EXISTS子句:

?


1

2

3

4

5

6

7

8

9

SELECT SalesOrderID,

       RevisionNumber,

       OrderDate

FROM   Sales.SalesOrderHeader

WHERE  EXISTS (SELECT 1

               FROM   sales.SalesPerson

               WHERE  SalesYTD > 3000000

                      AND SalesOrderHeader.SalesPersonID 

                        = Sales.SalesPerson.BusinessEntityID)

执行这条SQL语句的时候,会作如下的对比:

  1. WHERE子句返回所有EXISTS子句为TRUE的记录.
  2. EXIST子句使用相关子查询. 外部查询通过SalesPersonID关联到内部查询.
  3. 只有SalesYTD大于三百万美元的SalesPersons才会包含在结果之中.
  4. 如果子查询返回一行或多行记录,EXISTS子句返回TRUE.

EXISTS条件是一种成员条件,即只有返回结果它才返回TRUE.相反的,如果我们要测试非成员条件,我们可以使用NOT EXISTS.

当无记录返回时,NOT EXISTS返回TRUE.这样,如果我们想找出,所有由销售人员记录的,从年初至今,小于等于三百万美元的销售订单,我们可以使用如下的查询:

?


1

2

3

4

5

6

7

8

9

SELECT SalesOrderID,

       RevisionNumber,

       OrderDate

FROM   Sales.SalesOrderHeader

WHERE  NOT EXISTS (SELECT 1

               FROM   sales.SalesPerson

               WHERE  SalesYTD > 3000000

                      AND SalesOrderHeader.SalesPersonID 

                        = Sales.SalesPerson.BusinessEntityID)

gones945
翻译于 2个月前

0人顶

 翻译的不错哦!

NULL是怎么回事?

当一个子查询返回null值的时候,EXISTS会返回什么:  NULL, TRUE, 还是 FALSE?

坦白讲,我也很吃惊.

我很确信它会返回NULL, 但让人吃惊的是,我获知它返回TRUE。 因此,如果你的子查询返回null值,EXISTS子句会返回TRUE。 下面的例子会返回所有的SalesOrderHeader行,因为WHERE子句返回TRUE:

?


1

2

3

4

5

SELECT SalesOrderID,

       RevisionNumber,

       OrderDate

FROM   Sales.SalesOrderHeader

WHERE  EXISTS (SELECT NULL)

当我们学习IN操作符的时候,我们会发现,这是EXISTS子句所独有的特性.

IN 和 NOT IN

我们首先在如何过滤查询结果的课程中学习IN操作符。在子查询中使用的时候,IN 和 NOT IN 子句是一样的。下面是那篇文章的小结。

gones945
翻译于 2个月前

0人顶

 翻译的不错哦!

IN 和 NOT IN 回顾

IN操作符被看作是一个成员类型。成员类型允许在一条语句中进行多次匹配测试。例如,假如有公司领导的多个拼写形式,如“Owner”,“President”,和“CEO”。在这种情况下,你可以使用IN操作符来找到所有的匹配形式:

?


1

ContactTitle IN (‘CEO‘‘Owner‘‘President‘)

如果ContactTitle是“CEO”,“Owner"或者“President",上面的语句将匹配或者返回TRUE。为了使用IN操作符,需要使用逗号分隔测试项,并括在括号中。例子中完整的语句是:

?


1

2

3

4

5

6

SELECT CompanyName, ContactName, ContactTitle

FROM Customers

WHERE ContactTitle IN (‘CEO‘‘Owner‘‘President‘);

Note:  The above query isn‘t meant for

the adventure works database

gones945
翻译于 2个月前

0人顶

 翻译的不错哦!

在子查询中使用IN

当在子查询中使用的时候,数据列表可以用子查询来代替。在这种情况下,使用子查询的优势是,它有助于让查询处于数据驱动的状态,同时更易于处理。

我的意思是,你无需硬编码数据。

例如,如果你正在做一个查询,需要查找销售最多的销售人员的订单,非子查询的方式使用IN的语句是:

?


1

2

3

4

5

6

7

8

9

10

SELECT SalesOrderID,

       OrderDate,

       AccountNumber,

       CustomerID,

       SalesPersonID,

       TotalDue

  FROM Sales.SalesOrderHeader

  WHERE SalesPersonID IN (279, 286, 289)

whose results are

但是,现在我们知道了子查询,我们可以使用下面的语句获取同样的数据:

?


1

2

3

4

5

6

7

8

9

10

SELECT SalesOrderID,

       OrderDate,

       AccountNumber,

       CustomerID,

       SalesPersonID,

       TotalDue

  FROM Sales.SalesOrderHeader

  WHERE SalesPersonID IN (SELECT BusinessEntityID

                            FROM Sales.SalesPerson

                           WHERE Bonus > 5000)

其优势在于,随着销售人员销售的数据变化,返回的SalesPersonID的数据也跟着调整。

和其它的查询一样,你可以使用IN子句来创建一个关联子查询。这和EXIST子句使用的是相同的查询。

它返回了,从年初至今,所有销售人员记录的大于三百万美元的销售订单,但是现在我们使用IN子句:

?


1

2

3

4

5

6

7

8

9

SELECT SalesOrderID,

       RevisionNumber,

       OrderDate

FROM   Sales.SalesOrderHeader

WHERE  SalesPersonID IN (SELECT SalesPerson.BusinessEntityID

               FROM   sales.SalesPerson

               WHERE  SalesYTD > 3000000

                      AND SalesOrderHeader.SalesPersonID 

                        = Sales.SalesPerson.BusinessEntityID)

如果在比较列表中测试值 找到了 ,IN返回TRUE。如果在比较列表中测试值 没有找到 ,NOT IN返回TRUE。采用和上面一样的查询,我们可以找到,从年初至今,所有销售人员记录的小于等三百万美元的销售订单,查询语句如下:

?


1

2

3

4

5

6

7

8

9

SELECT SalesOrderID,

       RevisionNumber,

       OrderDate

FROM   Sales.SalesOrderHeader

WHERE  SalesPersonID NOT IN (SELECT SalesPerson.BusinessEntityID

               FROM   sales.SalesPerson

               WHERE  SalesYTD > 3000000

                      AND SalesOrderHeader.SalesPersonID 

                        = Sales.SalesPerson.BusinessEntityID)

gones945
翻译于 2个月前

0人顶

 翻译的不错哦!

在IN中碰到NULL是怎么回事?

当比较列表值包含NULL值的时候,和此列表比较的任何数据均返回false。

例如:

?


1

2

3

4

5

SELECT SalesOrderID,

       RevisionNumber,

       OrderDate

FROM   Sales.SalesOrderHeader

WHERE  SalesOrderID  IN (SELECT NULL)

返回0行。这是因为IN子句总是返回false。和EXISTS比起来,即便子查询返回NULL,EXISTS还是返回true。

比较修饰符

比较操作符,如大于,小于,等于和不等于,可以在WHERE子句中修改为更加有趣的方式,来完成比较。

使用 > 仅仅只能比较单一值 (标量值) ,你可以使用 > ANY 或者 > ALL 比较某列的值和子查询返回的列表数据。

gones945
翻译于 2个月前

0人顶

 翻译的不错哦!

使用 > ANY 修饰符

比较操作符>ANY意味着大于一个或多个列表项的值。也就是说会大于列表内的最小值。因此公式

?


1

Sales > ANY (1000, 2000, 2500)

会在销售量大于1000时返回TRUE,等同于语句:

?


1

Sales > MIN(1000, 2000, 2500)

简化为:

?


1

Sales > 1000

注意:你可以看到某些查询使用SOME。查询语句在使用SOME时返回的结果等同于ANY。即>ANY相同于>SOME。

我们以adventure works数据库为例,查找可能在安全库存等级的产品列表。具体说就是我们要查询的是安全库存等级大于平均安全库存等级的产品列表。

使用查询语句:

?


1

2

3

4

5

6

7

8

SELECT ProductID,

       Name,

       SafetyStockLevel,

       DaysToManufacture

FROM   Production.Product

WHERE  SafetyStockLevel > ANY (SELECT   AVG(SafetyStockLevel)

                               FROM     Production.Product

                               GROUP BY DaysToManufacture)

子查询首先计算平均安全库存等级。它返回一个数值列表。然后对每一个产品行的安全库存等级对外查询比较。如果它大于一个或多个列表中的值,就会被包含在结果中返回。

2015
翻译于 2个月前

1人顶

 翻译的不错哦!

如我一样,你可能第一反应是>ANY是多余的,鸡肋。它就等同于>MIN(...),不是吗?

这是可以用ANY,却不能用MIN的示例语句:

?


1

2

3

4

5

6

7

8

SELECT ProductID,

       Name,

       SafetyStockLevel,

       DaysToManufacture

FROM   Production.Product

WHERE  SafetyStockLevel > MIN((SELECT   AVG(SafetyStockLevel)

                               FROM     Production.Product

                               GROUP BY DaysToManufacture)

并不能运行,而是返回一个错误, “Cannot perform an aggregate function on an expression containing an aggregate or a subquery.” [译者注:不能运行的原因是GROUP BY语句对聚合函数不能用常规关键字操作,而是用另一些代替,例如GROUP BY条件中遇到聚合函数时WHERE用HAVING替换。]

使用 > ALL 修饰符

> ALL 修饰符是返回所有比内查询中结果都大的结果。

比较操作>ALL意味着要大于列表中最大的值。示例如下:

?


1

Sales > ALL (1000, 2000, 2500)

等同于:

?


1

Sales > MAX(100020002500)

对条件 Sales > 2500返回为TRUE

这个例子我们返回年初至今 奖金大于 所有销售收入小于$1000000人员的奖金 的销售人员名单:

?


1

2

3

4

5

6

7

8

9

10

11

12

SELECT p.BusinessEntityID,

       p.FirstName,

       p.LastName,

       s.Bonus,

       s.SalesYTD

FROM   Person.Person AS p

       INNER JOIN Sales.SalesPerson AS s

       ON p.BusinessEntityID = s.BusinessEntityID

WHERE  s.Bonus > ALL (SELECT Bonus

                      FROM   Sales.SalesPerson

                      WHERE  Sales.SalesPerson.SalesYTD 

                             < 1000000)

2015
翻译于 2个月前

0人顶

 翻译的不错哦!

各种比较修饰符小结

你能使用各种比较修饰符进行其他的操作,比如判断相等。如下表格内的示例可以更加便于理解。有些组合可能没有意义,我还是全部列了出来。

示例中的子查询结果集仅包含了三个数值:  1,2,3.

某些比较的组合根本没用。比如“= ALL” 或 “<> ANY.”。工具在于人使用,如果你觉得MAX或MIN可以用就该用,ANY和ALL只出现在它该出现的地方。

我们今天讨论了我在子查询中使用EXISTS和NOT EXISTS的情况。我用了相当多的IN子句,但通常是在一个静态列表,而不是子查询中。

转载于开源中国社区 http://www.oschina.net/translate/get-ready-to-learn-sql-server-using-subqueries

时间: 2024-10-27 13:45:26

在 SQL Server 数据库的 WHERE 语句中使用子查询的相关文章

sql server 数据库机种 insert 语句用法insert into emproyee(e_name,e_sex)values(&#39;唐家三少&#39;,0); insert into emproyee

刚倒弄sql server 对insert 语句插入多条数据时总结下> 单条数据插入: insert into emproyee(e_name,e_sex)values('唐家三少',0); insert into emproyee(e_name,e_sex)select'骷髅精灵',0 多条数据插入: insert into emproyee(e_name,e_sex)select'天蚕土豆',0 union all select '我吃西红柿',0 union all select '逆苍天

SQL Server调优系列基础篇(子查询运算总结)

原文:SQL Server调优系列基础篇(子查询运算总结) 前言 前面我们的几篇文章介绍了一系列关于运算符的介绍,以及各个运算符的优化方式和技巧.其中涵盖:查看执行计划的方式.几种数据集常用的连接方式.联合运算符方式.并行运算符等一系列的我们常见的运算符.有兴趣的童鞋可以点击查看. 本篇我们介绍关于子查询语句的一系列内容,子查询一般是我们形成复杂查询的一些基础性操作,所以关于子查询的应用方式就非常重要. 废话少说,开始本篇的正题. 技术准备 数据库版本为SQL Server2008R2,利用微软

数据库开发基础-SQl Server 主键、外键、子查询(嵌套查询)

主键 数据库主键是指表中一个列或列的组合,其值能唯一地标识表中的每一行.这样的一列或多列称为表的主键,通过它可强制表的实体完整性.当创建或更改表时可通过定义 PRIMARY KEY约束来创建主键.一个表只能有一个 PRIMARY KEY 约束,而且 PRIMARY KEY 约束中的列不能接受空值.由于 PRIMARY KEY 约束确保唯一数据,所以经常用来定义标识列. 主键的作用 主键的主要作用如下: (1)保证实体的完整性: (2)加快数据库的操作速度: (3) 在表中添加新记录时,数据库会自

在update语句中使用子查询

在update 中的 where 子句中使用子查询: UPDATE mg_page_log as a  SET  page_num=1 WHERE id in( SELECT id  from mg_page_log WHERE id < 100 GROUP BY visit_id) 会报: You can't specify target table 'a' for update in FROM clause 错误 所以正确的是: UPDATE mg_page_log as a ,( SELE

SQL Server 数据库部分常用语句小结

1. 查询某存储过程的访问情况 SELECT TOP 1000 db_name(d.database_id) as DBName, s.name as 存储名字, s.type_desc as 存储类型, d.cached_time as SP添加到缓存的时间, d.last_execution_time AS 上次执行SP的时间, d.last_elapsed_time as [上次执行SP所用的时间(微秒)], d.total_elapsed_time [完成此SP的执行所用的总时间(微秒)

[SQL Server 2005/2008] select语句中指定索引

一般情况下,SQL Server的查询优化器会对查询做优化,选择适合的索引. 当遇到一些宽表,索引和where 过滤条件多时, 查询优化器选择的可能并不是最佳的索引, 此时需要手动指定索引.具体效果可以在“执行计划中查看”. select * from 表名 with (nolock, index(索引表)) where ........

SQL Server的优化器会缓存标量子查询结果集吗

在这篇博客"ORACLE当中自定义函数性优化浅析"中,我们介绍了通过标量子查询缓存来优化函数性能: 标量子查询缓存(scalar subquery caching)会通过缓存结果减少SQL对函数(Function)的调用次数, ORACLE会在内存中构建一个哈希表来缓存标量子查询的结果. 那么SQL Server的优化器是否也会有类似这样的功能呢? 抱着这样的疑问,动手测试了一下,准备测试环境 CREATE TABLE TEST (    ID  INT );     DECLARE

【MYSQL】update/delete/select语句中的子查询

update或delete语句里含有子查询时,子查询里的表不能在update或是delete语句中,如含有运行时会报错:但select语句里含有子查询时,子查询里的表可以在select语句中. 如:把总成绩小于100的学生名称修改为天才 select stu_id from score group by stu_id having sum(grade)<100; #查询总成绩小于100的学生IDupdate students set name='天才' where id in (select s

SQL Server 数据库的SELECT 语句基本用法介绍

一.    基本语法结构 (1) 新建查询 如何查询表的所有内容 SELECT * FROM表名 (2) 选中查询列 如何查询指定表中的指定列,查询多列得用英文’,’隔开 SELECT字段1,字段2,字段…… FROM表名 (3) 如何为列指定别名(AS关键字) (4) 语句大小写的区别 select.字段等关键字大小写的区别 条件里的大小写区别 (5) 运算符介绍 加减乘除:+ - * / 比较运算符:><>= <= <> 二.    查询脚本 (1) 查询stude