合并多个结果集 SQL语言的高级用法

SQL Server admin 26℃ 0评论

GPS平台、网站建设、软件开发、系统运维,找森大网络科技!
https://cnsendnet.taobao.com
来自森大科技官方博客
http://www.cnsendblog.com/index.php/?p=2060

 

合并多个结果集 SQL语言的高级用法

第二章 SQL语言的高级用法

2.8 合并多个结果集
UNION 操作符可以把两个或多个SELECT语句的结果集合并起来。
当你想查询的数据在不同的地方,并且无法由一个查询语句得到时,你可以使用操作符UNION。使用操作符UNION时,要注意下列注意事项和原则:

SQLServer要求UNION子句中引用的所有表都具有相似的数据类型、相同的字段数,并且在每个查询中,选择列表里字段的顺序也必须相同。 SQL Server将自动删除结果集中的重复记录。但是,如果你指定了选项ALL,结果集中的所有记录都将被返回。 你必须在第一个SELECT语句中指定字段名。因此如果你想为结果集定义新的字段名,你必须在第一个SELECT语句中创建字段别名。 如果你希望结果集中的记录按一定顺序排列,你必须在UNION子句中用ORDER BY指定排序方式。否则,结果集中记录的顺序就可能不是你希望得到的。 你可以把一个复杂的查询分解成若干个SELECT语句,并用操作符UNION合并结果集,这样你会发现查询速度会有所提高。

下面的例子合并了两个结果集。第一个结果集从表customers中返回每个顾客的字段姓名、城市和邮政编码。第二个结果集从表employees中返回每个雇员的姓名、城市和邮政编码。当使用操作符UNION合并这两个结果集时,请注意第一个结果集中所指定的字段的别名。

USE northwind
SELECT( firstname+ ‘’+ lastname ) AS name,city,postalcode
FROM employees
UNION
SELECT companyname,city,postalcode
FROM customers
GO
运行结果:
name city postalcode
Alfreds Futterkiste Berlin 12209
Ana Trujillo Emparedados y helados México D.F. 05021
Antonio Moreno Taquería México D.F. 05023
Around the Horn London WA1 1DP
(100row(s)affected)

 

第二章 SQL语言的高级用法

2.9 子查询介绍
一个查询语句嵌套在一个SELECT语句、INSERT语句、UPDATE语句、DELETE语句或其他的子查询语句时,则称这个语句为子查询(subqueries)。你通常可以用连接语句(JOIN)代替一个子查询,你也可以用一个子查询代替一个表达式。
子查询可以把一个复杂的查询分解成一系列的逻辑步骤,这样就可以用一个单个的语句解决一个复杂的查询问题。当查询依赖于另一个查询的结果时,子查询会很有用。
一般情况下,包含子查询的查询语句也可以被写作连接语句。查询语句,不论含有连接还是子查询,它们的执行效率都差不多。当查询优化器遇到子查询语句时,通过用语法上类似的连接语句代替这个子查询,因此子查询和连接语句具有相同的执行计划,经过这样的优化步骤后,连接与子查询的执行效率将大同小异。区别在于子查询可能要求查询优化器执行额外的操作,例如排序,而这些操作将会影响查询的处理策略。
连接将使查询优化器以效率最高地方式查询数据,如果查询不要求多个步骤,就不需要使用子查询。
当你决定要使用子查询时,应注意以下事项:
子查询要用括号括起来; 只要需要一个值或一系列的值,你就可以用子查询代替一个表达式。可以用子查询返回一个含有多个字段的结果集,这个表可以代替一个表或完成一个连接语句的操作; 子查询不能查询包含数据类型是text或image的字段; 子查询中也可以再包含子查询,嵌套可以多至32层。

2.9.1 把子查询用作派生的表
可以用子查询产生一个派生的表,用于代替FROM子句中的表。派生表是FROM子句中子查询的一个特殊用法,用一个别名或用户自定义的名字来引用这个派生表。FROM子句中的子查询将返回一个结果集,这个结果集所形成的表将被外层SELECT语句使用。
在下面的例子中,内层查询用子查询产生了一个派生的表,外层查询将使用内层查询的结果集。在功能上,派生表本身就等同于一个完整的查询,但为了便于说明,把派生表独立出来。

USE northwind
SELECT T.orderid, T.Customerid
FROM ( SELECT orderid,customerid
FROM orders) AS T
GO

当用子查询产生派生表时,必须考虑到:

查询语句中的一个结果集,被用做一个表; 代替了FROM子句中的表; 将与查询的其它部分一起参与优化。

2.9.2 把子查询用作表达式
在Transact-SQL中,所有使用表达式的地方,都可以用子查询代替。此时子查询必须返回一个单个的值或某一个字段的值。子查询可以返回一系列的值来代替出现在WHERE子句中的IN关键字的表达式。
当子查询被用作表达式时,必须考虑到:

被当作一个表达式处理并计算。查询优化器总是将一个表达式等同于连接一个只有一行记录的表; 在整个语句中,只执行一次。

下面的例子返回一本畅销的计算机书的价格,所有书的平均价格,及该书和所有书的平均价格的差价。

USE pubs ·
SELECT title,price
,(SELECT AVG (price) FROM titles) AS average
,price – (SELECT AVG (price) FROM titles ) AS difference
FROM titles
WHERE type = popular_comp’
GO

2.9.3 用子查询关联数据
相关子查询可被用作动态表达式,这个表达式的值相对于外层查询的每一行而变化。
查询处理器为外层查询的每一个记录计算子查询的值,一次一行,而这个子查询每次都会被作为一个表达式而被计算并返回给外层查询。相关子查询是动态执行的子查询和外层查询间的一个非常有效的组合。
通常,一个查询可以写成多种方式,但得到的结果都相同。相关子查询把一个复杂的查询分解成为两个或多个简单的、相关的查询。
使用相关子查询时,内层子查询被反复执行,对外层查询的每一行,内层查询就要执行一次。

SQLSewer为外层查询的每一条记录执行一次内层查询; SQLSewer将比较内层查询的结果和外层查询的结果。

下面的例子返回订购了23号产品20件以上的顾客的列表:

USE northwind
SELECT orderid, customerid
FROM orderS AS or1
WHERE 20 < (SELECT quantity
FROM [Order details] AS od
WHERE or1.orderid = od.orderid AND od.productid = 23)
GO
运行结果:
orderid customerid
10337 FRANK
10348 WANDK
10396 FRANK
10402 ERNSH
10462 CONSH
(11 row(s) affected)

下面的例子从表orderdetails中返回每种产品订购数量最多的列表。请注意这里的相关子查询和外层查询引用了同一个表,查询优化器通常把这当作一个子连接。

USE northwind
SELECT DISTINCT productid,quantity
FROM [order details] AS ordl
WHERE quantity = (SELECT MAX (quantity)
FROM [order details] AS ord2
WHERE ordl.productid:ord2.productid)
GO
运行结果:
productid quantity
50 40
67 40
4 50
9 50
11 50
(77row(s)affected)

2.9.4 模拟连接子句
你可以用一个相关子查询产生一个结果集,这个结果集与连接(JOIN)所产生的结果集是相同的,例如,从某个表中查询数据,然后从外层查询中引用这个表。
下面的例子用相关子查询搜索被多个出版商出版的书的类型。为了防止语法的混乱不清,要求使用表的别名,用以区分两个titles表各自代表的含义。

USE pubs
SELECT DISTINCT t1.type
FROM titles AS t1
WHERE t1.type IN
(SELECT t2.type
FROM titles AS t2
WHERE t1.pub_id <> t2.pub_id)
GO
运行结果:
Type
business
psychology
(2 row(s) affected)

下面的例子所返回的结果集与前面的例子相同,但使用的不是相关子查询,而是子查询。

USE pubs
SELECT DISTINCT t1.type
FROM titles AS tl
INNER JOIN titles AS t2
ON t1.type = t2.type
WHERE t1.pub_id <> t2.pub_id
GO

2.9.5 模拟HAVING子句
相关子查询产生的结果集可以模拟HAVING子句产生的结果集。
下面的例子查询同类书中价格大于平均价格的所有书的书名。对于t1中每一个可能的记录,SQL Server都将执行这个子查询,如果某条记录的价格大于计算出的平均价格,就把这条记录放到结果集中。你不需要在语句中显式地使用分组语句,因为计算平均价格的子查询中,WHERE子句已经对书的类型进行了限制。

USE pubs
SELECT t1.type,t1.title,t1.price
FROM titles AS t1
WHERE t1.price > ( SELECT AVG(t2.price) FROM titles AS t2
WHERE t1.type = t2.type)
GO
运行结果:
Resulttype title
Business The Busy Executive™s Database Guide
Business Straight Talk About Computers
mod_cook Silicon Valley Gastronomic Treats
popular_comp But Is It User Friendly?
Psychology Computer Phobic AND Non-Phobic
Individuals: Behavior Variations
Psychology Prolonged Data Deprivation: Four Case
Studies
trad_cook Onions, Leeks, and Garlic: Cooking

Secrets of the Mediterranean
(7row(s)affected)

下面的例子产生的结果集和前面的例子相同,但它用的是含有GROUPBY和HAVING子句的子连接语句。

USE pubs
SELECT t1.type, t1.title, t1.price
FROM tities AS t1
INNER JOIN titles AS t2
ON t1.type = t2.type
GROUP BY t1.type,t1.title, t1.price
HAVING t1.priCe > AVG(t2.price)
GO

注意:可以用相关子查询模拟一个JOIN和HAVING子句产生的结果集,但查询处理器实现它们的方式可能不同。
2.9.6 使用EXISTS和NOT EXIST子句
可以用EXISTS和NOT EXISTS子句判断某个值是否在一系列的值中。
EXISTS和NOT EXISTS子句和相关子查询一同使用时,可以限制外层查询,使其结果集符合子查询的条件。基于某一条记录是否满足子查询,EXISTS和NOT EXISTS子句将返回TRUE或FALSE。
当子查询和EXISTS或NOT EXISTS子句共同使用时,SQL Server将测试数据是否匹配子查询结果集的某一条记录。其实并没有返回任何记录。当SQL Server知道至少有一条记录满足子查询中的WHERE条件时,就将结束数据搜索。
当SQLServer处理一个包含EXISTS或NOTEXISTS的子查询时:

外层查询测试子查询返回的记录是否存在; 基于查询所指定的条件,子查询返回TRUE或FALSE; 子查询不产生任何数据。

下面的例子在WHERE子句中使用了含有EXISTS子句的相关子查询,它将返回在2000年4月10日订购产品的雇员。

USE northwind
SELECT lastname, employeeid
FROM employees AS e
WHERE EXISTS ( SELECT * FROM orders AS o WHERE e.employeeid = o.employeeid
AND o.orderdate = ’10/4/2000’
GO
运行结果:
IaStname empIOyeeid
Peacock 4
King 7
(2row(s)affected)

下面的例子返回的结果集和前面例子的一样,这个例子表明你也可以用连接操作,而不是相关子查询,达到同样的目的。请注意这个查询需要使用关键字DISTINCT,只为每个雇员产生一条记录。

USE northwind
SELECT DISTINCT lastname, e.employeeid
FROM orders AS o
INNER JOIN employees AS e
ON o.employeeid = e.employeeid
WHERE O.Orderdate = ‘10/4/2000’
GO

 

 

GPS平台、网站建设、软件开发、系统运维,找森大网络科技!
https://cnsendnet.taobao.com
来自森大科技官方博客
http://www.cnsendblog.com/index.php/?p=2060

转载请注明:森大科技官方博客 » 合并多个结果集 SQL语言的高级用法

喜欢 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址