第二章 单表查询

第二章  单表查询

2.1 SELECT语句的元素

   SELECT语句的目的是对表进行查询,应用一定的逻辑处理,并返回结果。

示例1 示例查询

USE TSQLFundamentals2008;

 

SELECT empid,YEAR(orderdate) AS orderyear , COUNT(*) AS numorders

FROM Sales.Orders

WHERE custid = 71

GROUP BY empid,YEAR(orderdate)

HAVING COUNT(*) > 1

ORDER BY empid,orderyear;

各子句在逻辑上按一下顺序进行处理:

1. FROM

2. WHERE

3. GROUP BY

4. HAVING

5. SELECT

6. ORDER BY

逻辑上应该按照一下顺序进行处理:

FROM Sales.Orders

WHERE custid = 71

GROUP BY empid,YEAR(orderdate)

HAVING COUNT(*) > 1

SELECT empid,YEAR(orderdate) AS orderyear , COUNT(*) AS numorders

ORDER BY empid,orderyear

 

2.1.1 FROM子句

     在FROM子句中指定想要查询的表名,在SELECT子句中指定想要返回的各个属性。

  SELECT orderid,custid,empid,orderdate,freight FROM Sales.Orders

2.1.2 WHERE子句

     只有能让逻辑表达式返回TRUE的行,才能由WHERE阶段返回给后续的逻辑处理阶段。

     SELECT orderid,empid,custid,freight FROM Sales.Orders WHERE custid=71 

     T-SQL使用的是三值谓词逻辑: TRUE   FALSE   UNKNOWN。

     【注意】  TRUE  !=  NOT FALSE

2.1.3 GROUP BY子句

     GROUP BY阶段可以将前面逻辑查询处理阶段返回的行按“组”进行组合。每个组由在GROUP BY子句中指定的各元素决定。

 如果涉及到分组,那么GROUP BY阶段之后的所有阶段(包含HAVING,SELECT以及ORDER BY)的操作对象都是组,而不是单独的行。 

因为聚合函数只为每个组返回一个值,所以一个元素如果不在GROUP BY列表中出现,就只能作为聚合函数(COUNT,MAX,SUM,AVG,MIN)的输入。

所有的聚合函数都会忽略NULL值,只有一个例外——COUNT(*)

SELECT empid,YEAR(orderdate),SUM(freight),COUNT(*) AS orderdate

FROM Sales.Orders

WHERE custid=71

GROUP BY empid,YEAR(orderdate)

YEAR函数orderdate列的年份部分。

 

SELECT empid,YEAR(orderdate),COUNT(DISTINCT custid)

FROM Sales.Orders

GROUP BY empid,YEAR(orderdate)

如果只想处理不重复的已知值,可以在聚合函数括号中指定DISTINCT 关键字。

2.1.3 HAVING子句

只有能让逻辑表达式返回TRUE的组,才能由HAVING阶段返回给后续的逻辑处理阶段。

    SELECT empid,YEAR(orderdate)

FROM Sales.Orders

WHERE custid=71

GROUP BY empid,YEAR(orderdate)

HAVING COUNT(*)>1

2.1.5 SELECT子句

SELECT子句用于指定需要在查询返回的结果集中包含的属性(列)。

为目标列取别名: 表达式  AS  别名(最佳实践)

【注意】SELECT子句是在FROM,WHERE,GROUP BY以及HAVING子句之后处理的,这意味着对于SELECT子句之前处理的那些子句,在SELECT子句中为表达式分配的别名并不存在。

错误示例1:

SELECT orderid,YEAR(orderdate) as orderyear

FROM Sales.Orders

WHERE orderyear>2006

解决办法是使用同一个表达式:

SELECT orderid,YEAR(orderdate) as orderyear

FROM Sales.Orders

WHERE YEAR(orderdate)>2006

 

在SELECT子句内部也不能引用同一SELECT子句中创建的别名列。

错误示例2:

SELECT YEAR(orderdate) AS orderyear,orderyear+1 AS nextyear

FROM Sales.Orders

为了确保SELECT语句执行的结果中行的唯一性,SQL提供的方法就是使用DISTINCT子句来删除多余的行。

SELECT DISTINCT empid , YEAR(orderdate) AS orderyear

FROM Sales.Orders

2.1.6 ORDER BY子句

ORDER BY子句用于展示数据时对输出结果中的行进行排序(升序ASC和降序DESC)。

ORDER BY子句是唯一能引用SELECT处理阶段创建的列别名的阶段,因为它是唯一一个在SELECT阶段之后被处理的阶段。

SELECT empid,YEAR(orderdate) AS orderyear

FROM Sales.Orders

ORDER BY empid,orderyear ASC

T-SQL支持在ORDER BY子句中指定没有在SELECT子句中出现过的元素。也就是说,排序依据的列并不一定要在输出返回的列中选取。

SELECT firstname,lastname,country

FROM HR.Employees

ORDER BY hiredate DESC;

【注意】

当指定了DISTINCT以后,ORDER BY子句就被限制为只能选取SELECT列表中出现的那些元素。

错误示例3:

SELECT DISTINCT country 

FROM HR.Employees

ORDER BY hiredate;

2.1.7 TOP选项

    TOP选项是T-SQL特有的,用于限制查询返回的行数或百分比。

从逻辑查询的角度来看,TOP选项是作为SELECT阶段的一部分而处理的,紧挨着DISTINCT子句处理之后(如果存在DISTINCT)。

【注意】

当在查询中指定了TOP之后,ORDER BY子句就会起到双重作用。

(1)作为SELECT处理阶段的一部分的TOP选项要依靠ORDER BY子句先为各个行定义它们的逻辑优先顺序,在这种顺序的基础上再去过滤其他请求。

(2)作为SELECT处理阶段之后的ORDER BY阶段,与为了展示数据而对行进行排序的ORDER BY子句完全一样。

SELECT TOP(5) orderid,orderdate 

FROM Sales.Orders

ORDER BY orderdate DESC

 

在TOP中可以使用PERCENT关键字,在这种情况下,SQL Server会按照百分比来计算应该返回的满足条件的行数(向上取整)。

SELECT TOP(2) PERCENT orderid,orderdate

FROM Sales.Orders

ORDER BY orderdate DESC

 

如果想让查询是确定的,就要让ORDER BY列表能唯一的决定一行。换句话说,就是要为ORDER BY列表增加一个附加属性(附加属性是一个允许唯一的排列元素的属性或属性列表)。

WITH TIES选项:

SELECT TOP(5) WITH TIES orderid,orderdate

FROM Sales.Orders

ORDER BY orderdate DESC;

 

 

2.1.7 OVER子句

 OVER子句用于为行定义一个窗口,以便进行特定的运算。可以把行的窗口简单的认为是运算将要操作的一个行的集合。

聚合开窗函数使用OVER子句提供窗口作为上下文,对窗口中的一组值进行操作,而不是使用GROUP BY子句提供的上下文。这样就不必对数据进行分组,还能在同一行中同时返回基础行的列和聚合列。

带有空括号的OVER子句会提供所有的行进行计算。这里的所有的行并不一定是在FROM子句中出现的那些表中的所有行,而是在FROM,WHERE,GROUP BY,HAVING处理阶段完成之后仍然可用的那些行。

只有在SELECT阶段和ORDER BY阶段才允许使用OVER子句。

SELECT orderid,custid,val,SUM(val) OVER() AS total ,SUM(val) OVER(PARTITION BY custid) AS custtotalvalue

FROM Sales.OrderValues

 

OVER子句的一个优点就是:

(1)能够在返回基本列的同时,在同一个行对它们进行聚合。

(2)也可以在表达式中混合使用基本列和聚合值列。

SELECT  orderid,custid,val,100.*val / SUM(val) OVER() , 100.*val/SUM(val) 

     OVER(PARTITION BY custid)

FROM Sales.OrderValues; 

 OVER也支持四种排名函数:

ROW_NUMBER:用于为查询的结果集的各行分配递增的序列号,其逻辑顺序通过OVER子句中的ORDER BY语句进行指定。

SELECT orderid,custid,ROW_NUMBER() OVER(ORDER BY orderid) AS rownumber

FROM Sales.OrderValues

RANK和DENSE_RANK:RANK表示之前具有多少行更低的排序值

       DENSE_RANK表示之前具有多少个更低的排序值

SELECT orderid,custid,val ,ROW_NUMBER() OVER(ORDER BY val) AS rownumber,

   RANK() OVER(ORDER BY custid) AS rank,

   DENSE_RANK() OVER(ORDER BY custid) AS denserank

FROM Sales.OrderValues

 

 

【注意】

RANK和DENSE_RANK不同于ROW_NUMBER的地方是:

RANK和DENSE_RANK为具有相同排序值的所有行生成同一个序列号!

NTILE:可以把结果集中的行关联到组(tile,相当于由行组成的指定数目的组),并为每一行分配一个所属组的编号。

SELECT orderid,custid,val,NTILE(10) OVER(ORDER BY val)

FROM Sales.OrderValues

 

posted on 2010-01-25 20:37  张念  阅读(430)  评论(0编辑  收藏  举报

导航