开发学院数据库DB2 DB2 SQL 与 XQuery 教程,第 4 部分: 数据分析 阅读

DB2 SQL 与 XQuery 教程,第 4 部分: 数据分析

 2009-11-28 00:00:00 来源:WEB开发网   
核心提示:开始之前关于本系列本教程为您讲解 SQL 的一些基础和高级话题以及 XQuery 的基础知识,并展示如何使用 SQL 查询或 XQuery 语句将常被问起的业务问题表达为数据库查询,DB2 SQL 与 XQuery 教程,第 4 部分: 数据分析,开发人员和数据库管理员可以使用本教程来提高他们的数据库查询技能,Acad

开始之前

关于本系列

本教程为您讲解 SQL 的一些基础和高级话题以及 XQuery 的基础知识,并展示如何使用 SQL 查询或 XQuery 语句将常被问起的业务问题表达为数据库查询。开发人员和数据库管理员可以使用本教程来提高他们的数据库查询技能。Academic Initiative 成员可以使用本教程系列作为他们数据库课程的一部分。

本文中的所有例子都是基于 Aroma,这是一个示例数据库,其中包含了在美国各地的商店中出售的咖啡和茶用品的销售数据。每个例子由以下三部分组成:

以日常用语表达的一个业务问题

以 SQL 或 XQuery 表达的一个或多个例子查询

显示从数据库返回的结果的一个表

本指南是为了让读者学习 SQL 语言和 XQuery 而设计的。和学习任何其他技能一样,重要的是一边学习一边实践。本指南给出的表定义和数据为此提供了便利。

对于使用本指南作为学校课程一部分的学生而言,他们应该向老师学习连接到 Aroma 数据库的操作,并了解本指南的设置与您本地设置的不同之处。

本系列是针对于 DB2 Express-C 9 for UNIX®, Linux® and Windows® (曾用名 Viper)而编写的。

关于本教程

本教程描述如何编写需要进行某种数据分析的查询。很多查询包含连续计算,或对已排序的一组行执行的计算,这些都是在业务分析过程中常遇到的查询。例如:

每月的累加总计是多少?

按周计算的移动平均值是多少?

月销售额之间的排名是怎样的?

当前月的销售额占全年销售额的比例是多少?

DB2 9 中包含的标准 SQL OLAP 函数为回答这些类型的问题提供了有效的途径。通过使用在线分析处理(On-Line Analytical Processing,OLAP)函数,可以在查询结果中以标量值返回排名、行号和已有的列函数信息。OLAP 函数可以包括在一个 select 列表的表达式中或 select 语句的 ORDER BY 子句中。

本教程提供了一系列的例子,每个例子给出了业务查询和相关的语法。

本教程还展示如何使用标量函数从 DATE 列计算和提取信息,例如星期几和月份。

本章中的很多查询都依赖于聚合的销售总额。由于 Sales 表存储每日销售总额,因此数据库设计应包括用于回答这些查询的聚合表。

连接到数据库

在使用 SQL 查询或处理数据之前,需要连接到一个数据库。CONNECT 语句将一个数据库连接与一个用户名相关联。

如果您使用本指南作为学校课程的一部分,那么可以向老师询问要连接到的数据库的名称。对于本系列,数据库名为 aromadb。

要连接到 aromadb 数据库,可以在 DB2 命令行处理器中输入以下命令:

 CONNECT TO aromadb USER userid USING password

注意用老师告诉您的用户 ID 和密码替换 "userid" 和 "password"。如果不需要用户 ID 和密码,那么只需使用以下命令:

 CONNECT TO aromadb

如果看到下面的消息,则说明您已经建立一个成功的连接:

Database Connection Information 
Database server   = DB2/NT 9.0.0 
SQL authorization ID = USERID 
Local database alias = AROMADB

建立连接后,就可以开始使用数据库了。

累加总数

问题

Aroma Roma coffee 在 2006 年 1 月份的每日销售数字是多少?这个月的累加总销售额和累加总销售量是多少?

OLAP 查询

SELECT date, SUM(dollars) AS total_dollars, 
  SUM(SUM(dollars)) OVER(ORDER BY date ROWS UNBOUNDED PRECEDING) AS run_dollars, 
  SUM(quantity) AS total_qty, 
  SUM(SUM(quantity)) OVER(ORDER BY date ROWS UNBOUNDED PRECEDING) AS run_qty 
 FROM aroma.period a, aroma.sales b, aroma.product c 
 WHERE  a.perkey = b.perkey 
   AND c.prodkey = b.prodkey 
   AND c.classkey = b.classkey 
   AND year = 2006 
   AND month = 'JAN' 
   AND prod_name = 'Aroma Roma' 
 GROUP BY date 
 ORDER BY date;

结果

DateTotal_DollarsRun_DollarsTotal_QtyRun_Qty
2006-01-02855.50855.50118118
2006-01-03536.501392.0074192
2006-01-04181.251573.2525217
2006-01-05362.501935.7550267
2006-01-06667.002602.7592359
2006-01-07659.753262.5091450
2006-01-08309.503572.0054504
2006-01-09195.753767.7527531
2006-01-10420.504188.2558589
2006-01-11547.504735.7578667
2006-01-12536.505272.2574741
2006-01-13638.005910.2588829
2006-01-141057.506967.75150979
2006-01-15884.507852.251221101
2006-01-16761.258613.501051206
2006-01-17455.509069.00661272
2006-01-18768.509837.501061378
2006-01-19746.7510584.251031481
2006-01-20261.0010845.25361517
2006-01-21630.7511476.00871604
2006-01-22813.7512289.751151719
...

OLAP SUM 函数

OVER() 子句将简单的集合函数(SUM、MIN、MAX、COUNT 和 AVG)与 OLAP 聚合函数区分开来。

当窗口帧指定以下指令时,OLAP SUM 函数产生累加总计:

ROWS UNBOUNDED PRECEDING

这个指令告诉系统在结果集中之前的所有行上执行 OLAP 函数,在这个例子中就是 SUM 函数。也可以使用其他限制,例如 GROUP-BETWEEN 来指定所有行的一个子集。

OLAP ORDER BY 子句很关键。在这里指定 OLAP ORDER BY 子句,可以确保 OLAP SUM 函数的输入行是经过正确排序的(在这个例子中是按 Date 排序)。如果没有使用该指令,则输入行的逻辑顺序就可能是混乱的,这会导致累加总计得到的结果没有意义。该查询中的最后一个 ORDER BY 子句只对结果集的显示有影响,它与用于 LOAP 函数的 ORDER BY 子句是不同的。

OLAP ROW_NUMBER 函数

OLAP 函数甚至可用于一些简单的任务,例如在结果集中提供行号,就像下面的查询一样:

SELECT ROW_NUMBER() OVER() AS row_num, order_no, price 
FROM aroma.orders;

ROW_NUMORDER_NOPRICE
136001200.46
236011535.94
33602780.00
...

重设累加总计

问题

2006 年 1 月份 Aroma Roma 每个星期的累加销售数字是多少?

OLAP 查询

SELECT date, SUM(dollars) AS total_dollars, 
   SUM(SUM(dollars)) OVER(PARTITION BY week ORDER BY date 
   ROWS UNBOUNDED PRECEDING) AS run_dollars, 
   SUM(quantity) AS total_qty, 
   SUM(SUM(quantity)) OVER(PARTITION BY week ORDER BY date 
   ROWS UNBOUNDED PRECEDING) AS run_qty 
 FROM aroma.period a, aroma.sales b, aroma.product c 
 WHERE  a.perkey = b.perkey 
   AND c.prodkey = b.prodkey 
   AND c.classkey = b.classkey 
   AND year = 2006 
   AND month = 'JAN' 
   AND prod_name = 'Aroma Roma' 
 GROUP BY week, date 
 ORDER BY week, date;

结果

DateTotal_DollarsRun_DollarsTotal_QtyRun_Qty
2006-01-02855.50855.50118118
2006-01-03536.501392.0074192
2006-01-04181.251573.2525217
2006-01-05362.501935.7550267
2006-01-06667.002602.7592359
2006-01-07659.753262.5091450
2006-01-08309.503572.0054504
2006-01-09195.75195.752727
2006-01-10420.50616.255885
2006-01-11547.501163.7578163
2006-01-12536.501700.2574237
2006-01-13638.002338.2588325
2006-01-141057.503395.75150475
2006-01-15884.504280.25122597
2006-01-16761.25761.25105105
2006-01-17455.501216.7566171
2006-01-18768.501985.25106277
2006-01-19746.752732.00103380
2006-01-20261.002993.0036416
2006-01-21630.753623.7587503
2006-01-22813.754437.50115618
...

OLAP 窗口分割

当分割列中的值发生变化时,通过 OVER() 子句中的 OLAP PARTITION BY 子句可以重新设置计算。您可以按一个列或多个列对 OLAP 计算进行分割。

在这个查询中,虽然 PARTITION BY 子句中用到了 WEEK 列,但是显示的结果中不包含这一列。系统从 DATE 列得出某一天属于第几周。但是,如果在 select 列表中包括 WEEK 值,并使结果表的格式与之前的结果一致,那么查询的结果就更容易解释了。

下面是在 select 语句中包括 week 列的查询,以及该查询的输出。

SELECT date, SUM(dollars) AS total_dollars, 
 SUM(SUM(dollars)) OVER (PARTITION BY week ORDER BY date 
 ROWS UNBOUNDED PRECEDING) AS run_dollars, 
   SUM(quantity) AS total_qty, 
   SUM(SUM(quantity)) OVER(PARTITION BY week ORDER BY date 
 ROWS UNBOUNDED PRECEDING) AS run_qty, week 
 FROM aroma.period a, aroma.sales b, aroma.product c 
 WHERE  a.perkey = b.perkey 
   AND c.prodkey = b.prodkey 
   AND c.classkey = b.classkey 
   AND year = 2006 
   AND month = 'JAN' 
   AND prod_name = 'Aroma Roma' 
 GROUP BY week, date 
 ORDER BY week, date

结果

DATETOTAL_DOLLARSRUN_DOLLARSTOTAL_QTYRUN_QTYWEEK
2006-01-02855.50855.501181182
2006-01-03536.501392.00741922
2006-01-04181.251573.2525 2172
2006-01-05362.501935.75502672
2006-01-06667.002602.75923592
2006-01-07659.753262.50914502
2006-01-08309.503572.00545042
2006-01-09195.75195.7527273
2006-01-10420.50616.2558853
2006-01-11547.501163.75781633
2006-01-12536.501700.25742373
2006-01-13638.002338.25883253
2006-01-141057.503395.751504753
2006-01-15884.504280.251225973
2006-01-16761.25761.251051054
2006-01-17455.501216.75661714
2006-01-18768.501985.251062774
2006-01-19746.752732.001033804
2006-01-20261.002993.00364164
2006-01-21630.753623.75875034
2006-01-22813.754437.501156184
...

使用算术运算符

问题

2004 年每种产品的平均售价是多少?按照将总销售额除以总销售量的公式计算平均值。

例子查询

SELECT prod_name, SUM(dollars) AS total_sales, SUM(quantity) AS total_qty, 
    DEC(sum(dollars)/sum(quantity), 7, 2) AS price 
 FROM aroma.product a, aroma.sales b, aroma.period c 
 WHERE  a.prodkey = b.prodkey 
   AND a.classkey = b.classkey 
   AND c.perkey = b.perkey 
   AND year = 2004 
 GROUP BY prod_name 
 ORDER BY price;

结果

Prod_NameTotal_SalesTotal_QtyPrice
Gold Tips38913.75115633.36
Special Tips38596.00113903.38
Earl Grey41137.00113643.61
Assam Grade A39205.00107673.64
Breakfast Blend42295.50108803.88
English Breakfast44381.00107374.13
Irish Breakfast48759.00110944.39
Coffee Mug1054.002134.94
Darjeeling Number 162283.25115395.39
Ruby's Allspice133188.50234445.68
Assam Gold Blend71419.00116366.13
Colombiano188474.50275486.84
Aroma Roma203544.00283447.18
La Antigua197069.50268267.34
Veracruzano201230.00264697.60
Expresso XO224020.00285587.84
Aroma baseball cap15395.3519537.88
Lotta Latte217994.50269948.07
Cafe Au Lait213510.00263408.10
Aroma Sounds Cassette5206.006208.39
Xalapa Lapa251590.00292938.58
NA Lite231845.00258848.95
Demitasse Ms282385.25287439.82
Aroma t-shirt20278.50187010.84
Travel Mug1446.3513310.87
Darjeeling Special127207.001093111.63
Spice Sampler6060.0050512.00
Aroma Sounds CD7125.0055012.95
French Press, 2-Cup3329.8022414.86
Spice Jar4229.0023517.99
French Press, 4-Cup3323.6516719.90
Tea Sampler13695.0055024.90
...

使用算术运算符:( ), +, -, *, /

可以在 select 列表或搜索条件中执行算术运算符。下面的表中完整地列出了所有算术运算符。在这个表中,算术运算符按计算优先顺序从高到低(从上到下)排列,同一级别上则从左到右排列:

操作符名称
( )强制确定计算顺序
+, -正和负
*, /乘和除
+, -加和减

如果对一个表达式的计算顺序不确定,那么可以用括号来组织这个表达式。例如,对于表达式 (4 + 3 * 2),服务器算出它的值为 10,但是对于使用了括号的表达式 ((4 + 3) * 2),服务器算出它的值为 14。

使用中的注意事项

DEC 函数用于将 Price 值裁剪到只剩两个小数位:

          dec(sum(dollars)/sum(quantity), 7, 2) AS price

用 OLAP 比较累加总计

问题

在 2006 年 3 月份,西部和南部的累加日销售额相差多少?

OLAP 查询

SELECT t1.date, sales_cume_west, sales_cume_south, 
 sales_cume_west - sales_cume_south AS west_vs_south 
 FROM 
   (SELECT date, SUM(dollars) AS total_sales, 
     SUM(SUM(dollars)) OVER(ORDER BY date 
     ROWS UNBOUNDED PRECEDING) AS sales_cume_west 
   FROM aroma.market a, 
     aroma.store b, 
     aroma.sales c, 
     aroma.period d 
   WHERE  a.mktkey = b.mktkey 
     AND b.storekey = c.storekey 
     AND d.perkey = c.perkey 
     AND year = 2006 
     AND month = 'MAR' 
     AND region = 'West' 
   GROUP BY date) AS t1 
 JOIN 
   (SELECT date, SUM(dollars) AS total_sales, 
     SUM(SUM(dollars)) OVER(ORDER BY date 
     ROWS UNBOUNDED PRECEDING) AS sales_cume_south 
   FROM aroma.market a, 
     aroma.store b, 
     aroma.sales c, 
     aroma.period d 
   WHERE  a.mktkey = b.mktkey 
     AND b.storekey = c.storekey 
     AND d.perkey = c.perkey 
     AND year = 2006 
     AND month = 'MAR' 
     AND region = 'South' 
   GROUP BY date) AS t2 
 ON t1.date = t2.date 
 ORDER BY date;

结果

DATESales_Cume_WestSales_Cume_SouthWEST_VS_SOUTH
2006-03-012529.252056.75472.50
2006-03-026809.004146.752662.26
2006-03-039068.756366.552702.20
...
2006-03-29100513.8562891.3537622.50
2006-03-30104267.4065378.7538888.65
2006-03-31107222.1568100.7539121.40

OLAP ORDER BY 子句

使用 OLAP 进行连续计算的一个优点是可以将这些计算放在子查询中。OLAP 排序是函数本身的一部分,每个 OLAP 函数都有它自己的 ORDER BY 子句,这种子句独立于查询最终的 ORDER BY 子句。

在这个查询中,每个 OLAP 函数中都包括 ORDER BY DATE 子句,这是为了确保使用正确的值来计算累加总计。在查询的最后,有一个外层的 ORDER BY DATE 子句,该子句用于控制结果集的显示。

关于该查询要注意的地方

西部和南部累加总计销售额之间的比较是通过在 SELECT 语句中用简单的算术计算实现的。

移动平均值

销售数字会随着时间而波动。当销售数字剧烈波动时,会给观察深层次的、长远的趋势造成困扰。移动平均值就是用来克服这些波动的影响的。例如,一个三周的移动平均值就是将最近连续三周的总计除以 3 得到的。

问题

在 2005 年第 3 季度,圣何塞和迈阿密产品销售额的三周移动平均值是多少?

OLAP 查询

SELECT city, week, SUM(dollars) AS sales, 
   DEC(AVG(SUM(dollars)) OVER(partition by city 
   ORDER BY city, week ROWS 2 PRECEDING),7,2) AS mov_avg, 
   SUM(SUM(dollars)) OVER(PARTITION BY city 
   ORDER BY week ROWS unbounded PRECEDING) AS run_sales 
 FROM aroma.store a, 
   aroma.sales b, 
   aroma.period c 
 WHERE  a.storekey = b.storekey 
   AND c.perkey = b.perkey 
   AND qtr = 'Q3_05' 
   AND city IN ('San Jose', 'Miami') 
 GROUP BY city, week;

在下面的结果集中,注意每个城市的前两行中的平均值不是三周移动平均值,因为此处还没有足够的数据来完成那样的计算。相反,这两个平均值分别是在第一行(一周平均值)和前两行(两周平均值)上计算出来的。

结果

CityWeekSalesMov_avgRun_sales
Miami271838.551838.551838.55
Miami284482.153160.356320.70
Miami294616.70 3645.8010937.40
Miami304570.35 4556.4015507.75
Miami314681.95 4623.0020189.70
...
Miami385500.25 5235.0049493.35
Miami394891.40 5346.7154384.75
Miami403693.80 4695.1558078.55
...
San Jose273177.553177.553177.55
San Jose285825.804501.679003.35
San Jose298474.805826.0517478.15
San Jose307976.607425.7325454.75
San Jose317328.657926.6832783.40
San Jose326809.757371.6639593.15
San Jose337116.357084.9146709.50
...

DEC 函数用于定义在返回的结果中,Mov_Avg 列的值显示多少位数。

OLAP AVG 函数

OLAP AVG 函数是和下面的窗口帧一起使用的:

ROWS n PRECEDING

其中 n 是表示滑动因子的一个数字。在前面几个查询中,这个值通常是用关键字 unbounded 设置的。在这个查询中,由于需要基于三个行来计算移动平均值,因此插入值 2,表明是当前行加上前两行。

OLAP ORDER BY 子句确保 AVG 函数被应用到正确的移动连续行上(在这个例子中就是 WEEK)。PARTITION BY 子句标识出用于重设 AVG 函数的值(在这个例子中就是 CITY)。

OLAP SUM 函数

当窗口帧指定以下指令时,OLAP SUM 函数将产生移动总和:

ROWS n PRECEDING

这里也可以使用 FOLLOWING 关键字。

OLAP ORDER BY 子句很关键。这个子句用于确保 OLAP SUM 函数的输入行是经过正确排序的(在这个例子中是按 Date 的升序排列)。

排名

问题

西部各商店在销售总额方面的排名是怎样的?

OLAP 查询

SELECT store_name, district, SUM(dollars) AS total_sales, 
   RANK() OVER(ORDER BY SUM(dollars) DESC) AS sales_rank 
 FROM aroma.market a, 
   aroma.store b, 
   aroma.sales c, 
   aroma.period d 
 WHERE  a.mktkey = b.mktkey 
   AND b.storekey = c.storekey 
   AND d.perkey = c.perkey 
   AND year = 2005 
   AND month = 'MAR' 
   AND region = 'West' 
 GROUP BY store_name, district;

结果

Store_NameDistrictTotal_SalesSales_Rank
Cupertino Coffee SupplySan Francisco18670.501
Java Judy'sLos Angeles18015.502
Beaches BrewLos Angeles18011.553
San Jose Roasting CompanySan Francisco17973.904
Instant CoffeeSan Francisco15264.505
Roasters, Los GatosSan Francisco12836.506

首先计算 Sales 表中符合 WHERE 子句中搜索条件的每日销售额的总数,然后进行排名。

OLAP RANK 函数

IBM DB2 数据库支持一组 OLAP 排名函数,包括 RANK() 和 DENSE_RANK()。 这些函数不需要任何参数,因为 OLAP ORDER BY 子句定义了要排名的列或表达式。注意,OLAP 函数的默认排序顺序是升序(ASC),而业务查询常常不是按这个顺序排序的。为了从高到低排名(其中 1 是最高名次),必须在 OLAP ORDER BY 子句中指定 DESC 关键字。

DENSE_RANK 函数与 RANK 函数在一个方面存在区别:当使用 RANK 函数时,如果有两行或多行获得相同名次,那么接下来的行的名次就会跳跃下降。例如,如果有两个行的名次都是 2,那么这两行之后的那一行的名次就是 4(即 1,2,2,4)。当使用 DENSE_RANK 时,名次之间是连续的,不存在跳跃下降的现象。例如,如果有两个行的名次都是 8,那么这两行之后的那一行的名次仍然是 9,如下面的例子中所示:

SELECT prod_name, dollars, DENSE_RANK() OVER(ORDER BY dollars DESC) AS dense_rank, 
   RANK() OVER(ORDER BY dollars DESC) AS tie_rank 
 FROM aroma.product a, 
   aroma.sales b, 
   aroma.period c 
 WHERE  a.prodkey = b.prodkey 
   AND a.classkey = b.classkey 
   AND c.perkey = b.perkey 
   AND date = '01-03-2006';

结果

PROD_NAMEDOLLARSDENSE_RANKTIE_RANK
Espresso Machine Italiano499.7511
Cafe Au Lait392.0022
Veracruzano360.0033
Lotta Latte328.0044
NA Lite306.0055
Colombiano283.5066
Darjeeling Special207.0077
Colombiano202.5088
Colombiano202.5088
Expresso XO201.50910
Xalapa Lapa195.501011
...

使用 DATE 运算

问题

计算给定日期前 90 天的日期和后 90 天的日期。

例子查询

SELECT date - 90 DAYS AS due_date, 
   date AS cur_date, 
   date + 90 DAYS AS past_due 
 FROM aroma.period 
 WHERE year = 2004 
   AND month = 'JAN';

结果

Due_DateCur_DatePast_Due
2003-10-032004-01-012004-03-31
2003-10-042004-01-022004-04-01
2003-10-052004-01-032004-04-02
...

加减日期

可以对一个日期进行加减运算。为此,必须指定以下信息:

被加或被减的值(列名或日期时间表达式)

指定增量度量的日期单位。可以是天、月、年或这些值的组合。

增量的正或负。

关于该查询

这个例子查询计算一个给定日期的前 90 天的日期和后 90 天的日期。该函数以 ANSI SQL 92 日期时间格式返回值。

一定要弄清应加减哪个值。例如,在大多数情况下 "90 days" 并不等于 "3 months"。如果将前面的查询改为 3 months,那么很可能会得到不同的结果集:

SELECT date - 3 MONTHS AS due_date, 
   date AS cur_date, 
   date + 3 MONTHS AS past_due 
 FROM aroma.period 
 WHERE year = 2004 
   AND month = 'JAN';

结果

Due_DateCur_DatePast_Due
2003-10-012004-01-012004-04-01
2003-10-022004-01-022004-04-02
2003-10-032004-01-032004-04-03
...

如果不小心的话,这些差异会变得令人费解。为确保能得到需要的信息,您应该注意一些特殊情况,例如闰年。

还可以加减几个值的组合,例如:

SELECT date - 3 MONTHS - 4 DAYS AS due_date, 
   date AS cur_date, 
   date + 3 MONTHS + 4 DAYS AS past_due 
 FROM aroma.period 
 WHERE year = 2004 
   AND month = 'JAN';

结果

Due_DateCur_DatePast_Due
2003-09-272004-01-012004-04-05
2003-09-282004-01-022004-04-06
2003-09-292004-01-032004-04-07
...

类似地,您可以加减任何 TIME 数据类型的各个部分(HOURS、MINUTES 和/或 SECONDS)或任何 TIMESTAMP 数据类型的各个部分(YEARS、MONTHS、DAYS、HOURS、MINUTES 和/或 SECONDS)。

使用 HAVING 子句排除分组

问题

2005 年有哪些产品的总销售额低于 $25000?

例子查询

SELECT prod_name, sum(dollars) AS total_sales 
 FROM aroma.product a, aroma.sales b, aroma.period c 
 WHERE  a.prodkey = b.prodkey 
   AND a.classkey = b.classkey 
   AND c.perkey = b.perkey 
   AND year = 2005 
 GROUP BY prod_name 
 HAVING sum(dollars) < 25000 
 ORDER BY total_sales DESC;

结果

Prod_NameTotal_Sales
Aroma t-shirt21397.65
Espresso Machine Royale18119.80
Espresso Machine Italiano17679.15
Coffee Sampler16634.00
Tea Sampler14907.00
Aroma baseball cap13437.20
Aroma Sheffield Steel Teapot8082.00
Spice Sampler7788.00
Aroma Sounds CD5937.00
Aroma Sounds Cassette5323.00
French Press, 4-Cup4570.50
Spice Jar4073.00
French Press, 2-Cup3042.75
Travel Mug1581.75
Easter Sampler Basket1500.00
Coffee Mug1258.00
Christmas Sampler1230.00

分组上的条件:HAVING 子句

虽然将数据划分到分组可以减少返回的信息量,但是查询常常仍然会返回不需要的信息。您可以使用 HAVING 子句来排除不满足指定条件的分组,例如以销售总额小于或大于某个数作为条件。

这个查询计算每种产品在 2005 年的销售总额,然后只保留销售总额低于 $25000 的那些查询。

HAVING 子句的语法

SELECT column name(s) 
 FROM table name(s) 
 [WHERE search_condition] 
 [GROUP BY group_list] 
 [HAVING condition] 
 [ORDER BY order_list];

  
condition一个 SQL 条件,其中可以包括集合函数

HAVING 子句与 WHERE 子句有以下区别:

WHERE 子句HAVING 子句
对分组之前的行有影响对分组之后的结果集有影响
条件不能用集合函数(例如 SUM 或 AVG)表达,但是可以为非聚合表达式使用列别名条件可以用任何集合函数和列别名表达

使用中的注意事项

HAVING 子句中的条件可以引用任何集合函数。带有 HAVING 子句的查询必须包含一个 GROUP BY 子句,惟一的例外是 select 列表只包含集合函数。例如:

SELECT MIN(prodkey), MAX(classkey) 
 FROM aroma.product 
 HAVING MIN(prodkey) = 0;

结束语

本教程是系列教程中的第 4 部分,本教程描述了如何:

使用 SQL OLAP 函数执行数据分析;

使用 DATE 标量函数和 DATE 运算从 DATETIME 列计算和提取信息。

分析函数

SQL OLAP 函数可用于回答要求计算排名、比例、移动总和和移动平均值等诸多业务问题。本教程中的例子主要集中在可以由 OLAP 函数处理的一些计算上面。一般来说,OLAP 函数非常灵活,可以大大简化复杂的 SQL。

本文示例源代码或素材下载

Tags:DB SQL XQuery

编辑录入:爽爽 [复制链接] [打 印]
[]
  • 好
  • 好的评价 如果觉得好,就请您
      0%(0)
  • 差
  • 差的评价 如果觉得差,就请您
      0%(0)
赞助商链接