楼梯T-SQL:超越基础水平3:建立一个相关子查询

Gregory Larsen,2014 / 03 / 05

该系列              本文是系列的一部分:楼梯楼梯T-SQL:超越基础              下面就从他的楼梯T-SQL DML、Gregory Larsen覆盖的T-SQL语言如子查询更先进的方面。              在这楼梯2级我讨论如何在Transact-SQL语句中使用子查询。这楼梯水平将扩大对查询主题的讨论类型的查询称为相关子查询。我将探讨什么是相关子查询以及它是如何不同于普通的子查询。此外,我将提供你一些事务的SQL语句,超越基本的例子和使用相关子查询来帮助识别返回的行的结果集,以满足复杂的业务需求。              相关子查询是什么?              在这楼梯2级我们得知一个正常的子查询是一个SELECT语句,在另一个Transact-SQL语句,在子查询可以独立运行的外部查询返回结果。相关子查询是一种形式的子查询不能独立运行的外部查询,因为它包含了从外部查询的一个或多个列。相关子查询,就像一个正常的子查询,有时被称为内部查询。如果相关子查询(内查询)是独立运行的外部查询将返回一个错误。由于内部查询的执行依赖于外部查询的值,则称为相关子查询。              相关子查询可以执行多次。它将在外部查询中选择的每个候选行运行一次。每个候选人排列的值将被用来为外部查询栏目内的相关子查询每个执行提供值。一个声明中包含一个相关子查询将基于对相关子查询每个执行结果的最终结果。              相关子查询实例样本数据              为了演示如何使用相关子查询我需要一些测试数据。而不是创建自己的测试数据,我所有的例子将使用adventureworks2008r2数据库。如果你想跟着我,跑在您的环境中的例子你可以从这里下载adventureworks2008r2数据库:http://msftdbprodsamples.codeplex.com/releases/view/93587              在一个相关子查询的WHERE子句的例子              展示一个相关子查询的WHERE子句中使用的假设,我想找出那些CustomerID已经购买了70多个款式。为了完成这个需求,我可以运行代码:

SELECT CustomerID FROM Sales.SalesOrderHeader OH
WHERE (SELECT COUNT(*) FROM Sales.SalesOrderDetail
         WHERE SalesOrderID = OH.SalesOrderID) > 70;

清单1:相关子查询的WHERE子句中              当我运行清单1中的代码时,我得到了报表1中的输出。

CustomerID
-----------
29712
29722
30048
30107

报表1:运行清单1中的代码返回的结果              如果你回顾清单1中的代码,你会看到我约束我,通过使用相关子查询。子查询的代码是在圆括号中的我的相关子查询代码清单1和清单2中放。

SELECT COUNT(*) FROM Sales.SalesOrderDetail
         WHERE SalesOrderID = OH.SalesOrderID

清单2中的代码清单1所示:              如果您运行清单2中的代码,我会发现我在报告2中显示了一个错误。

Msg 4104, Level 16, State 1, Line 3
The multi-part identifier "OH.SalesOrderID
" could not be bound.

报表2:运行清单2中的代码时出错              我得到错误显示在报告2因为我的相关子查询包含一个参考列oh.salesorderid是从外部查询的列。由于所有相关子查询引用一个或多个列,从外部查询你不能独立于外部查询与之相关的。事实上,你不能运行查询独立于整个Transact-SQL语句的区别在于,相关子查询在一个正常的子查询。              这里给出的例子是使用相关子查询在WHERE子句中一个很平凡的例子。希望通过这样一个简单的例子很容易理解一个正常的子查询和相关子查询的区别。通常一个相关子查询可能会相当复杂。另外,记住有可能满足您的业务需求而不使用相关子查询的其他方法。              正如你可以看到,写一个相关子查询是一个正常的查询非常相似,但你就是不能运行相关子查询独立于外部查询。              在HAVING子句相关子查询的例子              有时您可能希望通过外部查询使用不同的值来约束有子句。这是当你可以在HAVING子句中使用相关子查询。假设你必须写一个查询,计算那些在2008年度前购买超过150000美元产品的顾客的回扣金额。清单3中的代码计算返利金额为那些尊贵的客户通过使用相关子查询在HAVING子句。

SELECT Outer_H.[CustomerID]
     , SUM(Outer_H.[SubTotal]) AS TotalPurchase
, SUM(Outer_H.[SubTotal]) * .10 AS Rebate
FROM [Sales].[SalesOrderHeader] AS Outer_H
WHERE YEAR(Outer_H.[OrderDate]) = ‘2008‘
GROUP BY Outer_H.[CustomerID]
HAVING (SELECT SUM(Inner_H.[SubTotal]) FROM [Sales].[SalesOrderHeader] AS Inner_H
        WHERE Inner_H.[CustomerID] = Outer_H.[CustomerID]
AND YEAR(Inner_H.[OrderDate]) = ‘2008‘) > 150000
ORDER BY Rebate DESC;

清单3:HAVING子句相关子查询              当我运行清单5中的代码时,我在报告3中得到了结果。

CustomerID  TotalPurchase         Rebate
----------- --------------------- ---------------------------------------
29923       220496.658            22049.665800
29641       210647.4929           21064.749290
29617       187964.844            18796.484400
29913       186387.5613           18638.756130
29818       179916.2877           17991.628770
29940       175358.3954           17535.839540
29987       172169.4612           17216.946120
29736       157700.6034           15770.060340
29995       156984.5148           15698.451480
29770       151824.9944           15182.499440

报告3:运行清单3的结果              相关子查询清单3中的代码使用CustomerID从集团外部查询中的条款在相关子查询。相关子查询的执行将为每一行返回GROUP BY子句。这使得HAVING子句计算总金额的产品从外部查询卖给每个CustomerID的值求和,次全列每salesorderheader记录在记录与从外部查询相关信息。Transact-SQL语句在清单3中只返回一行,CustomerID在购买了价值超过150000美元的产品。

UPDATE语句包含一个相关子查询的例子              相关子查询不仅可以用于返回一个结果集,使用SELECT语句。还可以使用它们更新SQLServer表中的数据。为了证明这一点,我会先在tempdb表生成一些测试数据,通过使用清单4中的代码。

USE tempdb;
GO
SET NOCOUNT ON;
CREATE TABLE CarInventory (
ID int identity,
CarName varchar(50),
VIN varchar(50),
StickerPrice decimal (7,2),
InvoicePrice decimal (7,2));
GO
INSERT INTO CarInventory VALUES (‘Explorer‘,‘EXP2014123456A‘,46198.45,38201.87),
(‘Explorer‘,‘EXP2014123493A‘,47129.98, 38201.87),                              
(‘Grand Cherokee‘,‘JGC20141234345X‘,41678.45,36201.86),
(‘Grand Cherokee‘,‘JGC20141234556W‘,44518.31,36201.86),
(‘Pathfinder‘,‘NPF2014987365A‘,32587.73,28917.10),
(‘Pathfinder‘,‘NPF2014239657B‘,33577.54,28917.10),
(‘Pathfinder‘,‘NPF2014098587C‘,35876.12,28917.10),
(‘Tahoe‘,‘TAH201409674A‘,52001.08,46000.01);

清单4:创建和填充测试表的代码              清单4中的代码创建一个carinventory表然后填充八行代表车当前库存。              定期的销售经理喜欢通过运行清单5中的查询看到他的invoicepriceratio。

SELECT CarName, InvoicePrice/StickerPrice*100.0 AS InvoicePriceRatio
FROM CarInventory;

清单5:invoicepriceratio查询              当经理运行此查询她注意到有一些相同的发票价量有不同的invoicepriceratio值类似的汽车。为了最大化自己的发票价格比她问她写一个查询,将更新所有她的车,每一辆车的StickerPrice同carname值具有相同的invoicepriceratio IT支持。她希望这家伙把StickerPrice作为carname最高标价相同的值。这样,所有的汽车都有相同的carname值都有相同的stickerprice价值。为了完成这个更新的carinventory表,这家伙的交易清单6中的SQL语句,其中包含一个相关子查询。

UPDATE CarInventory 
SET StickerPrice = (SELECT MAX(StickerPrice)
                    FROM CarInventory Inner_CI
                    WHERE Inner_CI.CarName = Outer_CI.CarName) 
FROM CarInventory Outer_CI;

清单6:相关子查询更新carinventory Maximum Sticker Price              清单8中的代码使用在相关子查询的外部查询的carname确定每个独特的carname最大StickerPrice。这个最大的stickerprice价值在相关子查询发现,然后被用来更新stickerprice值为每个carinventory记录具有相同的carname。              相关子查询的性能考虑              有一些性能方面的考虑,你应该知道在编写Transact-SQL语句包含相关子查询。当外部查询包含少量行时,性能并不差。但是,当外部查询包含大量行时,它不会从性能角度很好地扩展。这是因为相关子查询需要外部查询中的每个候选行执行。因此,当外部查询包含越来越多的候选行相关子查询被执行多次,因此Transact-SQL语句将需要更长的时间来运行。如果你发现你的相关子查询的SQL语句的性能不能满足你的要求,那么你应该寻找替代解决方案,如使用内部或外部连接操作的查询,或是返回一个小数量的候选行从外部查询。              总结              相关子查询是一种内在的查询,包括从外部查询的一个或多个列。相关子查询被执行一次外部查询的每个候选行。因为一个相关子查询包含从外部查询不能列可独立运行的外部查询。相关子查询的地方,虽然没有规模从性能的角度来看,有大量的候选人排在外查询鉴定。

时间: 2024-10-14 06:01:14

楼梯T-SQL:超越基础水平3:建立一个相关子查询的相关文章

T-SQL的进阶:超越基本级别3:构建相关子查询——701小组

T-SQL的进阶:超越基本级别3:构建相关子查询 格雷戈里·拉森,2014/03/05 原文链接: http://www.sqlservercentral.com/articles/Stairway+Series/105972/ 该系列 这篇文章是进阶系列的一部分: t - sql的进阶:超越基础 从他的阶梯到T-SQL DML,Gregory Larsen涵盖了T-SQL语言的更高级的方面,如子查询. 在这个楼梯的第二层,我讨论了如何在Transact - T-SQL语句中使用子查询.这个楼梯

楼梯T-SQL:超越基础6级:使用CASE表达式和IIF函数

从他的楼梯到T-SQL DML,Gregory Larsen涵盖了更多的高级方面的T-SQL语言,如子查询. 有时您需要编写一个可以根据另一个表达式的评估返回不同的TSQL表达式的单个TSQL语句.当您需要这种功能时,您可以使用CASE表达式或IIF函数来满足此要求.在本文中,我将回顾CASE和IIF语法,并向您展示CASE表达式和IIF函数的示例. 了解CASE表达Transact-SQL CASE表达式允许您在TSQL代码中放置条件逻辑.此条件逻辑为您提供了一种在TSQL语句中放置不同代码块

SQL优化基础 使用索引(一个小例子)

按照本文操作和体会,会对sql优化有个基本最简单的了解,其他深入还需要更多资料和实践的学习: 1. 建表: 复制代码 代码如下: create table site_user ( id int IDENTITY(1,1) PRIMARY KEY, [name] varchar(20), code varchar(20), date datetime ) 2. 插入8万条数据 复制代码 代码如下: declare @m int set @m=1 while @m<80000 begin INSER

相关子查询【SQL Server】

查询book表中大于该类图书价格平均值的图书信息 先将第一条记录的类编号的值为2代入子查询中,子查询为 select avg(price) from book b where b.id=2 则得到类编号为2的书籍平均价格为(23+45)/2=34 再和外部查询做判断 select * from book a where price>34 然后再类编号为3的书籍中,再次通过比较 相关子查询(多值子查询) 1.非相关子查询(嵌套子查询)是独立于外部的子查询,子查询只会执行一次,相关查询可以执行多次,

SQL嵌套子查询和相关子查询的执行过程有什么区别(推荐)

SQLServer子查询可以分为 相关子查询 和 嵌套子查询 两类.前提, 假设Books表如下: 类编号 图书名 出版社 价格 -------------------------------------------------------- 2 c#高级应用 圣通出版 23.00 2 Jsp开发应用 机械出版社 45.00 3 高等数学 济南出版社 25.00 3 疯狂英语 清华大学出版社 32.00 嵌套子查询的执行不依赖与外部的查询. 执行过程: (1)执行子查询,其结果不被显示,而是传递

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

这是关于子查询语句的一系列文章中的第三篇.在这篇文章中我们将讨论WHERE语句中的子查询语句.其他的文章讨论了其他语句中的子查询语句. 本次课程中的所有例子都是基于Microsoft SQL Server Management Studio和AdventureWorks2012数据库的.读者可以阅读我的SQL Server使用入门学习使用这些免费的工具. 在WHERE语句中使用子查询 在WHERE语句中使用子查询是非常常见的.常见的用法是用EXISTS或IN测试存在性.在某些情况下重新考虑查询语

Oracle SQL语言基础及环境准备_超越OCP精通Oracle视频教程培训26

Oracle SQL语言基础及环境准备_超越OCP精通Oracle视频教程培训26 本课程介绍: Oracle视频教程,风哥本套oracle教程培训是<<Oracle数据库SQL语言实战培训教程>>的第1/5套:SQL语言之基础入门及环境准备.主要学习Oracle数据库SQL语言基础介绍.PL/SQL语言介绍.数据库SQL对象与数据类型介绍.SQL语言实战环境准备等. Oracle SQL语言之基础及环境准备,课程内容详细如下: Oracle数据库SQL语言基础介绍Oracle数据

JAVA-Unit03: SQL(基础查询) 、 SQL(关联查询)

Unit03: SQL(基础查询) . SQL(关联查询) 列别名 当SELECT子句中查询的列是一个函数 或者表达式时,那么查询出来的结果集 中对应的该字段的名字就是这个函数或者 表达式的名字.为此可以为这一列添加 别名,这样结果集中该字段就使用别名 作为该列的名字. 若希望别名区分大小写或者含有空格,那么 该别名可以使用双引号括起来. SELECT ename,sal*12 "s al" FROM emp AND,OR AND优先级高于OR,可以通过括号 提高优先级. SELECT

SQL Server基础

一.常用命令 1.使用命令行开启SQL Server服务 获取管理员权限的命令行工具: net start mssqlserver 开启sql server服务 net restart mssqlserver 重新启动sql server服务 net stop mssqlserver 关闭sql server服务 2.使用命令登陆(该方法可适用于在一台没有SQL Server的电脑去操作一台有SQL Server的电脑) 运行: sqpl ?/ [-S 服务器的名称]  [-U 登陆名] [-P