DMSQL总结
一. DM_SQL
(一)SQL语言概述
SQL:Structured Query Language,结构化查询语言,是一个通用的、功能强大的关系数据库语言,按照ANSI(美国国家标准协会)的规定,SQL被作为关系型数据库管理系统的标准语言,其主要功能就是同数据库建立联系,进行沟通,SQL命令可以完成几乎所有的数据库操作。
关系型数据库管理系统,如DM、Oracle、Sybase 、SQL Server、MYSQL、Access等都采用SQL语言标准。
(二)SQL的基本功能
数据定义:CREATE、DROP、ALTER
数据操纵:INSERT、UPDATE、DELETE
数据控制:GRANT、REVOKE
数据查询:SELECT
(三)SQL的基本对象
表空间 TABLESPACE
用户 USER
模式 SCHEMA
表 TABLE
视图 VIEW
列 COLUMN
存储过程 PROCEDURE
存储函数 FUNCTION
存储包 PACKAGE
触发器 TRIGGER
序列 SEQUENCE
索引 INDEX
数据字典 DICTIONARY
(四)SQL的基本操作
创建对象:CREATE TABLE TABNAME…
撤销对象:DROP TABLE TABNAME…
插入数据:INSERT INTO TABNAME…
更新数据:UPDATE TABNAME…
删除数据:DELETE FROM TABNAME…
查询数据:SELECT * FROM TABNAME…
授予权限:GRANT SELECT ON TABNAME TO…
回收权限:REVOKE SELECT ON TABNAME FROM…
(五)SQL语法要素
属性词 - Predicates
条件子句 - Clause
运算符 - Operator
操作数 - Operation
函数 - Function
SQL语句 - Statement
基本格式:命令+条件子句
(六)数据查询语句
- 语句格式
SELECT
[PREDICATE] {* TABLE.* [TABLE.]FIELD1[,
[TABLE.]FIELD2[,…]]}
FROM
TABLEEXPRESSION [,…]
[WHERE…]
[GROUP BY…]
[HAVING…]
[ORDER BY…]; - 单表查询
SELECT 语句仅从一个表/视图中检索数据,称单表查询。
(1) 简单查询
查询所有图书的名字、作者及当前销售价格,并消去重复。
SELECT DISTINCT NAME, AUTHOR, NOWPRICE FROM PRODUCTION.PRODUCT;
(2) 带条件查询
带条件查询是指在指定表中查询出满足条件的元组。该功能是在查询语句中使用WHERE 子句实现的。WHERE 子句常用的查询条件由谓词和逻辑运算符组成。谓词指明了一个条件,该条件求解后,结果为一个布尔值:真、假或未知。
逻辑运算符有:AND,OR,NOT。
谓词包括:比较谓词(=、>、?、>=、?=、?>),BETWEEN 谓词、IN 谓词、LIKE
谓词、NULL 谓词、EXISTS 谓词。
① 使用比较谓词查询
给出当前销售价格在 10~20 元之间的所有图书的名字、作者、出版社和当前价格。
SELECT NAME, AUTHOR, PUBLISHER, NOWPRICE FROM PRODUCTION.PRODUCT WHERE NOWPRICE>=10 AND NOWPRICE<=20;
② 使用BETWEEN谓词的查询
给出当前销售价格在 10~20 元之间的所有图书的名字、作者、出版社和当前价格。
SELECT NAME, AUTHOR, PUBLISHER, NOWPRICE FROM PRODUCTION.PRODUCT WHERE NOWPRICE BETWEEN 10 AND 20;
③ 使用IN谓词的查询
查询出版社为中华书局或人民文学出版社出版的图书名称与作者信息。
SELECT NAME, AUTHOR FROM PRODUCTION.PRODUCT WHERE PUBLISHER IN (‘中华书局’, ‘人民文学出版社’)
④ 使用 LIKE 谓词的查询
LIKE 谓词一般用来进行字符串的匹配。我们先用实例来说明 LIKE 谓词的使用方法。
查询第一通讯地址中第四个字开始为“关山”且以 202 结尾的地址。
SELECT ADDRESSID, ADDRESS1, CITY, POSTALCODE FROM PERSON.ADDRESS WHERE ADDRESS1 LIKE ‘___关山%202’;
⑤ 使用.ROW 进行 LIKE 谓词的查询
LIKE 谓词除支持使用列的计算外,还支持通过 ROW 保留字对表或视图进行 LIKE 计算。
该查询依次对表或视图中所有字符类型的列进行LIKE计算,只要有一列符合条件,则返回
TRUE。
其语法的一般格式为:<表名>.ROW LIKE <匹配字符串> [ ESCAPE <转义字符>]
查询评论中哪些与曹雪芹有关
SELECT * FROM PRODUCTION. PRODUCT_REVIEW WHERE PRODUCT_REVIEW.ROW LIKE ‘%曹雪芹%’;
⑥ 使用 NULL 谓词的查询
空值是未知的值。当列的类型为数值类型时,NULL 并不表示0;当列的类型为字符串类型时,NULL也并不表示空串。因为0和空串也是确定值。NULL只能是一种标识,表示它在当前行中的相应列值还未确定或未知,对它的查询也就不能使用比较谓词而须使用NULL谓词。
查询哪些人员的 EMAIL 地址为 NULL。
SELECT NAME, SEX, PHONE FROM PERSON.PERSON WHERE EMAIL IS NULL;
在 NULL 谓词前,可加 NOT 表示否定。
⑦ 组合逻辑
可以用逻辑算符(AND,OR,NOT)与各种谓词相组合生成较复杂的条件查询。
例查询当前销售价格低于15元且折扣低于7或出版社为人民文学出版社的图书名称和作者。
SELECT NAME, AUTHOR FROM PRODUCTION.PRODUCT WHERE NOWPRICE < 15 AND DISCOUNT < 7 OR PUBLISHER=‘人民文学出版社’;
(3) 集函数
为了进一步方便用户的使用,增强查询能力,SQL 语言提供了多种内部集函数。集函数
又称库函数,当根据某一限制条件从表中导出一组行集时,使用集函数可对该行集作统计操
作并返回单一统计值。
集函数经常与 SELECT 语句的 GROUP BY 子句一同使用。集函数对于每个分组只返回
一行数据。
集函数可分为 11 类:
COUNT();
相异集函数AVG|MAX|MIN|SUM|COUNT(DISTINCT<列名>);
完全集函数AVG|MAX|MIN|COUNT|SUM([ALL]<值表达式>);
方差集函数VAR_POP、VAR_SAMP、VARIANCE 、 STDDEV_POP 、STDDEV_SAMP、STDDEV;
协方差函数COVAR_POP、COVAR_SAMP、CORR;
首行函数FIRST_VALUE;
求区间范围内最大值集函数AREA_MAX;
FIRST/LAST集函数AVG|MAX|MIN|COUNT|SUM([ALL] <值表达式>) KEEP (DENSE_RANK FIRST|LAST ORDER BY子句);ORDER BY子句语法参考 4.7 ORDER BY 子句;
字符串集函数 LISTAGG/LISTAGG2、WM_CONCAT、COLLECT;
求中位数函数 MEDIAN;
线性回归相关REGR集函数REGR_COUNT、REGR_AVGX、REGR_AVGY、REGR_SLOPE、REGR_INTERCEPT、REGR_R2、REGR_SXX、REGR_SYY、REGR_SXY。
① 求最大值集函数 MAX 和求最小值集函数 MIN
查询折扣小于 7 的图书中现价最低的价格。
SELECT MIN(NOWPRICE) FROM PRODUCTION.PRODUCT WHERE DISCOUNT < 7;
查询结果为:6.1000
需要说明的是:SELECT后使用集函数MAX和MIN得到的是一个最大值和最小值,因而SELECT后不能再有列名出现,如果有只能出现在集函数中。如:
SELECT NAME,MIN(NOWPRICE) FROM PRODUCTION.PRODUCT;
DM 系统会报错,因为 NAME 是一个行集合,而最低价格是唯一值。
② 求平均值集函数 AVG 和总和集函数 SUM
例1求折扣小于 7 的图书的平均现价。
SELECT AVG(NOWPRICE) FROMPRODUCTION.PRODUCT WHERE DISCOUNT < 7;
查询结果为:23.15
例2求折扣大于 8 的图书的总价格。
SELECT SUM(NOWPRICE) FROM PRODUCTION.PRODUCT WHERE DISCOUNT >8;
查询结果为:25.5
③ 求总个数集函数 COUNT
例1查询已登记供应商的个数。
SELECT COUNT() FROM PURCHASING.VENDOR;
查询结果为:12
由此例可看出,COUNT(*)的结果是 VENDOR 表中的总行数,由于主关键字不允许有相同值,因此,它不需要使用保留字 DISTINCT。
例 2 查询目前销售的图书的出版商的个数。
SELECT COUNT(DISTINCT PUBLISHER) FROM PRODUCTION.PRODUCT;
查询结果为:9
由于一个出版商可出版多种图书,因而此例中一定要用 DISTINCT 才能得到正确结果。
④ 求方差集函数VARIANCE、标准差函数STDDEV和样本标准差函数STDDEV_SAMP
例 1 求图书的现价方差。
SELECT VARIANCE(NOWPRICE) FROM PRODUCTION.PRODUCT;
查询结果为:1.3664888888888888888888888888888888889E2
例 2 求图书的现价标准差。
SELECT STDDEV(NOWPRICE) FROM PRODUCTION.PRODUCT;
查询结果为:11.689692
例 3 求图书的现价样本标准差。
SELECT STDDEV_SAMP(NOWPRICE) FROM PRODUCTION.PRODUCT;
查询结果为:11.689692
⑤ 求总体协方差集函数 COVAR_POP、样本协方差函数 COVAR_SAMP 和相关系数CORR
例 1 求产品原始价格 ORIGINALPRICE 和当头销售价格 NOWPRICE 的总体协方差。
SELECT COVAR_POP(ORIGINALPRICE, NOWPRICE) FROM PRODUCTION.PRODUCT;
查询结果为:166.226
例 2 求产品原始价格 ORIGINALPRICE 和当头销售价格 NOWPRICE 的样本协方差。
SELECT COVAR_SAMP(ORIGINALPRICE, NOWPRICE) FROM PRODUCTION.PRODUCT;
查询结果为:1.8469555555555555555555555555555555556E2
例 3 求产品原始价格 ORIGINALPRICE 和当头销售价格 NOWPRICE 的相关系数。
SELECT CORR(ORIGINALPRICE, NOWPRICE) FROM PRODUCTION.PRODUCT;
查询结果为:9.6276530968E-001
⑥ 首行函数 FIRST_VALUE
例 返回查询项的首行记录。
SELECT FIRST_VALUE(NAME) FROM PRODUCTION.PRODUCT;
查询结果为:红楼梦
⑦ 求区间范围内的最大值函数 AREA_MAX
例 求图书的现价在 20~30 之间的最大值。
SELECT area_max(NOWPRICE,20,30) FROM PRODUCTION.PRODUCT;
查询结果为:25.5000
⑧ 求 FIRST/LAST 集函数
例 求每个用户最早定的商品中花费最多和最少的金额。
SELECT CUSTOMERID,max(TOTAL) keep (dense_rank first order by ORDERDATE) max_val, min(TOTAL) keep (dense_rank first order by ORDERDATE) min_val from SALES.SALESORDER_HEADER group by CUSTOMERID;
⑨ 求 LISTAGG/LISTAGG2集函数、求WM_CONCAT集函数、求COLLECT集函数
例 1 求出版的所有图书,分隔符为’, ',使用 LISTAGG/LISTAGG2。
SELECT LISTAGG(NAME, ', ') WITHIN GROUP (ORDER BY NAME) LISTAGG FROM PRODUCTION.PRODUCT;
或
SELECT LISTAGG2(NAME, ', ') WITHIN GROUP (ORDER BY NAME) LISTAGG FROM PRODUCTION.PRODUCT;
例 2 求每个出版社出版的所有图书。先根据出版社进行分组,然后将每个出版社出版
的图书名用“,”拼接起来,使用 WM_CONCAT。
SELECT PUBLISHER, WM_CONCAT(NAME) FROM PRODUCTION.PRODUCT GROUP BY PUBLISHER;
例 3 求出版的所有图书书名的嵌套表。
CREATE TYPE T_NAME AS TABLE OF VARCHAR;
/
SELECT CAST(COLLECT(NAME ORDER BY NAME) AS T_NAME) AS T_NAME FROM PRODUCTION.PRODUCT;
⑩ 求MEDIAN集函数
例 求按照 type 分组之后,各组内 nowprice 的中位数。
SELECT MEDIAN(nowprice)FROM PRODUCTION.PRODUCT group by(type);
11 求线性回归相关 REGR 集函数
例 1 以 ORIGINALPRICE 为自变量,NOWPRICE 为因变量,对 ORIGINALPRICE 和NOWPRICE 进行线性回归分析,求有效数据行数,自变量均值,因变量均值。
SELECT REGR_COUNT(NOWPRICE, ORIGINALPRICE) AS COUNT, REGR_AVGX(NOWPRICE, ORIGINALPRICE) AS AVGX, REGR_AVGY(NOWPRICE, ORIGINALPRICE) AS AVGY FROM PRODUCTION.PRODUCT;
例 2 以 ORIGINALPRICE 为自变量,NOWPRICE 为因变量,对 ORIGINALPRICE 和NOWPRICE 进行线性回归分析,求斜率,因变量截距,相关系数。
SELECT REGR_SLOPE(NOWPRICE, ORIGINALPRICE) AS SLOPE, REGR_INTERCEPT(NOWPRICE, ORIGINALPRICE) AS INTERCEPT,REGR_R2(NOWPRICE, ORIGINALPRICE) AS R2 FROM PRODUCTION.PRODUCT;
查询结果如下:
例 3 以 ORIGINALPRICE 为自变量,NOWPRICE为因变量,对ORIGINALPRICE和NOWPRICE 进行线性回归分析,求三种诊断统计量。
SELECT REGR_SXX(nowprice, originalprice) AS SXX, REGR_SYY(nowprice, originalprice) AS SYY,REGR_SXY(nowprice, originalprice) AS SXY FROM PRODUCTION.PRODUCT; - 连接查询
如果一个查询包含多个表(>=2),则称这种方式的查询为连接查询。即<FROM 子句>中使用的是<连接表>。DM 的连接查询方式包括:交叉连接(cross join)、自然连接(natural join)、内连接(inner)、外连接(outer)。
(1) 交叉连接
① 无过滤条件
对连接的两张表记录做笛卡尔集,产生最终结果输出。
例 SALESPERSON 和 EMPLOYEE 通过交叉连接查询 HAIRDATE 和 SALESLASTYEAR。
SELECT T1.HAIRDATE, T2.SALESLASTYEAR FROM RESOURCES.EMPLOYEE T1 CROSS JOIN SALES.SALESPERSON T2;
② 有过滤条件
对连接的两张表记录做笛卡尔集,根据 WHERE 条件进行过滤,产生最终结果输出。
例 查询性别为男性的员工的姓名与职务。
SELECT T1.NAME, T2.TITLE FROM PERSON.PERSON T1, RESOURCES.EMPLOYEE T2 WHERE T1.PERSONID = T2.PERSONID AND T1.SEX = ‘M’;
(2) 自然连接(NATURAL JOIN)
把两张连接表中的同名列作为连接条件,进行等值连接,我们称这样的连接为自然连接。
自然连接具有以下特点:
连接表中存在同名列;
如果有多个同名列,则会产生多个等值连接条件;
如果连接表中的同名列类型不匹配,则报错处理。
例 查询销售人员的入职时间和去年销售总额。
SELECT T1.HAIRDATE, T2.SALESLASTYEAR FROM RESOURCES.EMPLOYEE T1 NATURAL JOIN SALES.SALESPERSON T2;
(3) JOIN … USING
这是自然连接的另一种写法,JOIN 关键字指定连接的两张表,USING 指明连接列。要求USING中的列存在于两张连接表中。
例 查询销售人员的入职时间和去年销售总额。
SELECT HAIRDATE, SALESLASTYEAR FROM RESOURCES.EMPLOYEE JOIN SALES.SALESPERSON USING(EMPLOYEEID);
(4) JOIN…ON
这是一种连接查询的常用写法,说明是一个连接查询。JOIN关键字指定连接的两张表,ON 子句指定连接条件表达式,其中不允许出现 ROWNUM。具体采用何种连接方式,由数据库内部分析确定。
例 查询销售人员的入职时间和去年销售总额。
SELECT T1.HAIRDATE, T2.SALESLASTYEAR FROM RESOURCES.EMPLOYEE T1 JOIN SALES.SALESPERSON T2 ON T1.EMPLOYEEID=T2.EMPLOYEEID;
(5) 自连接
数据表与自身进行连接,我们称这种连接为自连接。
自连接查询至少要对一张表起别名,否则,服务器无法识别要处理的是哪张表。
例 对 PURCHASING.VENDOR 表进行自连接查询
SELECT T1.NAME, T2.NAME, T1.ACTIVEFLAG FROM PURCHASING.VENDOR T1, PURCHASING.VENDOR T2 WHERE T1.NAME = T2.NAME;
(6) 内连接(INNER JOIN)
根据连接条件,结果集仅包含满足全部连接条件的记录,我们称这样的连接为内连接。
例 从PRODUCT_CATEGORY、PRODUCT_SUBCATEGORY中查询图书的目录名称和子目录名称。
SELECT T1.NAME, T2.NAME FROM PRODUCTION.PRODUCT_CATEGORY T1 INNER JOIN PRODUCTION.PRODUCT_SUBCATEGORY T2 ON T1.PRODUCT_CATEGORYID = T2.PRODUCT_CATEGORYID;
因为PRODUCT_CATEGORY中的NAME为金融的没有对应的子目录,所以结果集中没有金融类的图书信息。
(7) 外连接(OUTER JOIN)
外连接对结果集进行了扩展,会返回一张表的所有记录,对于另一张表无法匹配的字段用 NULL 填充返回。DM 数据库支持三种方式的外连接:左外连接、右外连接、全外连接。外连接中常用到的术语:左表、右表。根据表所在外连接中的位置来确定,位于左侧的表,称为左表;位于右侧的表,称为右表。
例如 SELECT * FROM T1 LEFT JOIN T2 ON T1.C1=T2.D1,T1 表为左表,T2 表为右表。
返回所有记录的表根据外连接的方式而定。
左外连接:返回左表所有记录;
右外连接:返回右表所有记录;
全外连接:返回两张表所有记录。处理过程为分别对两张表进行左外连接和右外连接,然后合并结果集。
在左外连接和右外连接中,如果需要对未能匹配的缺失数据进行填充,可以使用分区外连接(PARTITION OUTER JOIN),分区外连接通常用于处理稀疏数据以得到分析报表。
例 1 从PRODUCT_CATEGORY、PRODUCT_SUBCATEGORY中查询图书的所有目录名称和子目录名称,包括没有子目录的目录。
SELECT T1.NAME, T2.NAME FROM PRODUCTION.PRODUCT_CATEGORY T1 LEFT OUTER JOIN PRODUCTION.PRODUCT_SUBCATEGORY T2 ON T1.PRODUCT_CATEGORYID = T2.PRODUCT_CATEGORYID;
例 2 从 PRODUCT_CATEGORY、PRODUCT_SUBCATEGORY 中查询图书的目录名称和所有子目录名称,包括没有目录的子目录。
SELECT T1.NAME, T2.NAME FROM PRODUCTION.PRODUCT_CATEGORY T1 RIGHT OUTER JOIN PRODUCTION.PRODUCT_SUBCATEGORY T2 ON T1.PRODUCT_CATEGORYID = T2.PRODUCT_CATEGORYID;
例 3 从 PRODUCT_CATEGORY、PRODUCT_SUBCATEGORY 中查询图书的所有目录名称和所有子目录名称。
SELECT T1.NAME, T2.NAME FROM PRODUCTION.PRODUCT_CATEGORY T1 FULL OUTER JOIN PRODUCTION.PRODUCT_SUBCATEGORY T2 ON T1.PRODUCT_CATEGORYID = T2.PRODUCT_CATEGORYID;
外连接还有一种写法,在连接条件或 WHERE 条件中,在列后面增加(+)指示左外连接或者右外连接。如果表 A 和表 B 连接,连接条件或者 where 条件中,A 的列带有(+)后缀,则认为是 B LEFT JOIN A。如果用户的(+)指示引起了外连接环,则报错。下面举例说明。
例 4 从 PRODUCT_CATEGORY、PRODUCT_SUBCATEGORY 中查询图书的目录名称
和所有子目录名称,包括没有目录的子目录。
SELECT T1.NAME, T2.NAMEFROM PRODUCTION.PRODUCT_CATEGORY T1, PRODUCTION.PRODUCT_SUBCATEGORY T2 WHERE T1.PRODUCT_CATEGORYID(+) = T2.PRODUCT_CATEGORYID;
例 5 新建产品区域销售统计表 SALES.SALESREGION 并插入数据。
CREATE TABLE SALES.SALESREGION(REGION CHAR(10), PRODUCTID INT, AMOUNT INT);
INSERT INTO SALES.SALESREGION VALUES(‘大陆’, 2, 19800);
INSERT INTO SALES.SALESREGION VALUES(‘大陆’, 4, 20090);
INSERT INTO SALES.SALESREGION VALUES(‘港澳台’, 6, 5698);
INSERT INTO SALES.SALESREGION VALUES(‘外国’, 9, 3756);
COMMIT;
统计每个产品在各个区域的销售量,没有销售则显示 NULL,此时可使用 PARTITON
OUTER JOIN 将稀疏数据转为稠密数据。
SELECT A.PRODUCTID, B.REGION, B.AMOUNT FROM PRODUCTION.PRODUCT A LEFT JOIN SALES.SALESREGION B PARTITION BY(B.REGION) ON A.PRODUCTID=B.PRODUCTID ORDER BY A.PRODUCTID, B.REGION;
(8) JOIN APPLY
JOIN APPLY 是指连接中的右表可以引用左表列,即同层列引用。通过对 APPLY 右侧输入求值来获得左侧输入每一行的计算结果,生成的行最终组合起来作为最终结果。CROSS APPLY 与CROSS JOIN功能类似,相当于不包含连接条件的CROSS JOIN。OUTER APPLY与 LEFT OUTER JOIN功能类似,相当于不包含连接条件的LEFT OUTER JOIN。
例 1 CROSS APPLY 右侧输入没有左侧输入的相关条件时,等价于 CROSS JOIN。
数据准备
CREATE TABLE T1(C1 INT,C2 INT);
CREATE TABLE T2(D1 INT,D2 INT);
INSERT INTO T1 VALUES(1,1);
INSERT INTO T1 VALUES(2,2);
INSERT INTO T2 VALUES(2,2);
INSERT INTO T2 VALUES(3,3);
COMMIT;
查询
SELECT * FROM T1 CROSS APPLY T2;
例 2 CROSS APPLY 右侧输入有左侧输入的相关条件时,通过对 CROSS APPLY 右侧输入求值来获得左侧输入每一行的计算结果,生成的结果行最终组合起来作为最终结果。
SELECT * FROM T1 CROSS APPLY(SELECT * FROM T2 WHERE C1=D1);
例 3 OUTER APPLY 结果集中既会返回结果集的行,又会返回不生成结果集的行。不生成结果集的行左孩子原样输出,右孩子补 NULL。
SELECT * FROM T1 OUTER APPLY(SELECT * FROM T2 WHERE C1=D1);
- GROUP BY 和 HAVING 子句
GROUP BY 子句主要用法是分类汇总。GROUP BY 子句一般与聚集函数一起使用,常见聚集函数包括 COUNT、SUM、AVG、MAX 和 MIN 等。
GROUP BY 子句将由 WHERE 子句返回的临时结果按一个或多个分组项进行分组,分组项相同的为一组。分组结果是行的集合。
HAVING 子句用于为组设置检索条件。
(1) GROUP BY子句的使用
GROUP BY 子句是 SELECT 语句的可选项部分。它定义了分组表。
例 1 统计每个部门的员工数。
SELECT DEPARTMENTID,COUNT(*) FROM RESOURCES.EMPLOYEE_DEPARTMENT GROUP BY DEPARTMENTID;
系统执行此语句时,首先将 EMPLOYEE_DEPARTMENT 表按 DEPARTMENTID 列进行分
组,相同的 DEPARTMENTID 为一组,然后对每一组使用集函数 COUNT(),统计该组内的
记录个数,如此继续,直到处理完最后一组,返回查询结果。
如果存在 WHERE 子句,系统先根据 WHERE 条件进行过滤,然后对满足条件的记录进
行分组。
例 2 求小说类别包含的子类别所对应的产品数量,并按子类别编号的升序排列。
SELECT A1.PRODUCT_SUBCATEGORYID AS 子分类编号,A3.NAME AS 子分类名,count()AS 数量FROM PRODUCTION.PRODUCT A1,
PRODUCTION.PRODUCT_CATEGORY A2,
PRODUCTION.PRODUCT_SUBCATEGORY A3
WHERE A1.PRODUCT_SUBCATEGORYID=A3.PRODUCT_SUBCATEGORYID
AND A2.PRODUCT_CATEGORYID=A3.PRODUCT_CATEGORYID
AND A2.NAME=‘小说’
GROUP BY A1.PRODUCT_SUBCATEGORYID,A3.NAME
ORDER BY A1.PRODUCT_SUBCATEGORYID;
使用 GROUP BY 要注意以下问题:
分组列不能为集函数表达式或者在 SELECT 子句中定义的别名;
当分组列值包含空值时,则空值作为一个独立组;
当分组列包含多个列名时,则按照 GROUP BY 子句中列出现的顺序进行分组;
GROUP BY 子句中至多可包含 512 个分组项;
ROLLUP\CUBE\GROUPING SETS 组合不能超过 8 个。
(2) ROLLUP 的使用
ROLLUP 主要用于统计分析,对分组列以及分组列的部分子集进行分组,输出用户需要
的结果。
例 按小区住址和所属行政区域统计员工居住分布情况。
SELECT CITY , ADDRESS1, COUNT(*) as NUMS FROM PERSON.ADDRESS GROUP BY ROLLUP(CITY, ADDRESS1);
上例中的查询等价于:
SELECT CITY , ADDRESS1, COUNT() AS NUMS FROM PERSON.ADDRESS GROUP BY
CITY, ADDRESS1 UNION ALL SELECT CITY , NULL, COUNT() AS NUMS FROM PERSON.ADDRESS GROUP BY CITY UNION ALL SELECT NULL , NULL, COUNT() AS NUMS FROM PERSON.ADDRESS GROUP BY 0;
使用 ROLLUP 要注意以下事项:
ROLLUP 项不能包含集函数;
不支持包含 WITH FUNCTION 的相关查询;
不支持包含存在 ROLLUP 的嵌套相关子查询;
不支持数组查询;
ROLLUP 项最多支持 511 个;
ROLLUP 项不能引用外层列。
(3) CUBE的使用
CUBE 的使用场景与 ROLLUP 类似,常用于统计分析,对分组列以及分区列的所有子集
进行分组,输出所有分组结果。
例 按小区住址、所属行政区域统计员工居住分布情况。
SELECT CITY , ADDRESS1, COUNT() AS NUMS FROM PERSON.ADDRESS GROUP BY CUBE(CITY, ADDRESS1);
上例中的查询等价于:
SELECT CITY , ADDRESS1, COUNT() AS NUMS FROM PERSON.ADDRESS GROUP BY CITY, ADDRESS1 UNION ALL SELECT CITY , NULL, COUNT() AS NUMS FROM PERSON.ADDRESS GROUP BY CITY UNION ALL SELECT NULL , ADDRESS1, COUNT() AS NUMS FROM PERSON.ADDRESS GROUP BY ADDRESS1 UNION ALL SELECT NULL , NULL, COUNT() AS NUMS FROM PERSON.ADDRESS;
使用 CUBE 要注意以下事项:
CUBE 项不能包含集函数;
不支持包含 WITH FUNCTION 的相关查询;
不支持包含存在 CUBE 的嵌套相关子查询;
不支持数组查询;
CUBE 项最多支持 9 个;
CUBE 项不能引用外层列。
(4) GROUPING的使用
GROUPING 可以视为集函数,一般用于含 GROUP BY 的语句中,标识某子结果集是否是按指定分组项分组的结果,如果是,GROUPING 值为 0;否则为 1。
使用约束说明:
- GROUPING 中只能包含一列;
- GROUPING 只能在 GROUP BY 查询中使用;
- GROUPING 不能在 WHERE 或连接条件中使用;
- GROUPING 支持表达式运算。例如 GROUPING(c1) + GROUPING(c2)。
例 按小区住址和所属行政区域统计员工居住分布情况。
SELECT GROUPING(CITY) AS G_CITY,GROUPING(ADDRESS1) AS G_ADD, CITY , ADDRESS1, COUNT(*) AS NUMS FROM PERSON.ADDRESS GROUP BY ROLLUP(CITY, ADDRESS1);
(5) GROUPING SETS 的使用
GROUPING SETS是对GROUP BY的扩展,可以指定不同的列进行分组,每个分组列
集作为一个分组单元。使用GROUPING SETS,用户可以灵活的指定分组方式,避免ROLLUP/CUBE过多的分组情况,满足实际应用需求。
GROUPING SETS的分组过程为依次按照每一个分组单元进行分组,最后把每个分组结
果进行UNION ALL输出最终结果。如果查询项不属于分组列,则用NULL代替。
例 按照邮编、住址和行政区域统计员工住址分布情况。
SELECT CITY , ADDRESS1, POSTALCODE, COUNT(*) AS NUMS FROM PERSON.ADDRESS GROUP BY GROUPING SETS((CITY, ADDRESS1), POSTALCODE);
上例中的查询等价于:
SELECT CITY , ADDRESS1, NULL , COUNT() AS NUMS FROM PERSON.ADDRESS GROUP BY CITY, ADDRESS1 UNION ALL SELECT NULL , NULL, POSTALCODE ,COUNT() AS NUMS FROM PERSON.ADDRESS GROUP BY POSTALCODE;
(6) GROUPING_ID的使用
GROUPING_ID表示参数列是否为分组列。返回值的每一个二进制位表示对应的参数列是否为分组列,如果是分组列,该位值为0;否则为1。
使用 GROUPING_ID 可以按照列的分组情况过滤结果集。
使用约束说明:
GROUPING_ID 中至少包含一列,最多包含 63 列;
GROUPING_ID 只能与分组项一起使用;
GROUPING_ID 支持表达式运算;
GROUPING_ID 作为分组函数,不能出现在 where 或连接条件中。
例 按小区住址和所属行政区域统计员工居住分布情况。
SELECT GROUPING(CITY) AS G_CITY,GROUPING(ADDRESS1) AS G_ADD, GROUPING_ID(CITY, ADDRESS1) AS G_CA,CITY , ADDRESS1, COUNT(*) AS NUMS FROM PERSON.ADDRESS GROUP BY ROLLUP(CITY, ADDRESS1);
(7) GROUP_ID的使用
GROUP_ID表示结果集来自于哪一个分组,用于区别相同分组的结果集。如果有N个相同分组,则GROUP_ID取值范围为 0~N-1。每组的初始值为 0。
当查询包含多个分组时,使用GROUP_ID可以方便的过滤相同分组的结果集。
使用约束说明:
GROUP_ID 不包含参数;
GROUP_ID 只能与分组项一起使用;
GROUP_ID 支持表达式运算;
GROUP_ID 作为分组函数,不能出现在 WHERE 或连接条件中。
例 按小区住址和所属行政区域统计员工居住分布情况。
SELECT GROUPING(CITY) AS G_CITY,GROUPING(ADDRESS1) AS G_ADD, GROUP_ID() AS GID,CITY , ADDRESS1, COUNT(*) AS NUMS FROM PERSON.ADDRESS GROUP BY ROLLUP(CITY, ADDRESS1), CITY;
(8) HAVING 子句的使用
HAVING 子句是 SELECT 语句的可选项部分,它也定义了一个分组表。
例 统计出同一子类别的产品数量大于 1 的子类别名称,数量,并按数量从小到大的顺序排列。
SELECT A2.NAME AS 子分类名, COUNT ()AS 数量
FROM PRODUCTION.PRODUCT A1,
PRODUCTION.PRODUCT_SUBCATEGORY A2
WHERE A1.PRODUCT_SUBCATEGORYID=A2.PRODUCT_SUBCATEGORYID
GROUP BY A2.NAME
HAVING COUNT()>1
ORDER BY 2;
系统执行此语句时,首先将PRODUCT表和PRODUCT_SUBCATEGORY表中的各行按相同的 SUBCATEGORYID作连接,再按子类别名的取值进行分组,相同的子类别名为一组,然后对每一组使用集函数 COUNT(),统计该组内产品的数量,如此继续,直到最后一组。
再选择产品数量大于 1 的组作为查询结果。
5. ORDER BY子句
ORDER BY 子句可以选择性地出现在<查询表达式>之后,它规定了当行由查询返回时
应具有的顺序
使用说明 :
ORDER BY 子句提供了要排序的项目清单和他们的排序顺序:递增顺序(ASC,默认)或是递减顺序(DESC)。它必须跟随在<查询表达式>之后,因为它是在查询计算得出的最终结果上进行操作的;
SIBLINGS 关键字必须与 CONNECT BY 一起配合使用,专门用于指定层次查询中相同层次数据返回的顺序。详见 4.13.5 层次查询层内排序;
用于指定排序列。支持<列说明>、<无符号整数>、<值表达式>或<布尔表达式>四种指定方式;
COLLATE 关键字指定该排序项根据 collation_name 中指定的排序规则进行排序。目前 collation_name 仅支持指定为 Chinese_PRC_CS_AS_KS_WS,当指定为该规则时,该排序项按照中文拼音排序。COLLATE 关键字仅适用于 VARCHAR 类型的列;
<值表达式> 语法支持,实际不起作用。例如,值表达式(如:-1,3×6)作为排序
列,将不影响最终结果表的行输出顺序。SELECT * FROM T ORDER BY 36;和 SELECT * FROM T;效果一样;
<布尔表达式> 如果指定了布尔表达式,则按照布尔表达式的结果 1 或 0 进行排序。
例如:在 SELECT * FROM T ORDER BY 1=2;语句中,因为布尔表达式 1=2 结果为 0,那么
系统按照每一行的排序键值均为 0 进行排序;
当排序列值包含 NULL 时,根据指定的“NULLS FIRST|LAST”决定包含空值的行是排在最前还是最后,缺省为 NULLS FIRST;
由于 ORDER BY 只能在最终结果上操作,不能将其放在查询中;
如果 ORDER BY 后面使用集函数,则必须使用 GROUP BY 分组,且 GROUP BY分组中必须包含查询列中所有列;
ORDER BY 子句中至多可包含 255 个排序列。
例 1 将 RESOURCES.DEPARTMENT 表中的资产总值按从大到小的顺序排列。
SELECT * FROM RESOURCES.DEPARTMENT ORDER BY DEPARTMENTID DESC;
等价于:
SELECT * FROM RESOURCES.DEPARTMENT ORDER BY 1 DESC;
例 2 因为查询列只有两列,而 ORDER BY 指定了第 3 列为排序列,则报错。
SELECT DEPARTMENTID,NAME FROM RESOURCES.DEPARTMENT ORDER BY 3;
系统报错:无效的 ORDER BY 语句。
6. FOR UPDATE子句
FOR UPDATE 子句可以选择性地出现在<查询表达式>之后。普通 SELECT 查询不会修改行数据物理记录上的 TID 事务号,FOR UPDATE 会修改行数据物理记录上的 TID 事务号并对该 TID 上锁,以保证该更新操作的待更新数据不被其他事务修改。
例 查询 RESOURCES.DEPARTMENT 表中的资产。
SELECT * FROM RESOURCES.DEPARTMENT FOR UPDATE;
//只要 FOR UPDATE 语句不提交,其他会话就不能修改此结果集。
需要说明的是:
① 以下情况 SELECT FOR UPDATE 查询会报错:
带 GROUP BY 的查询,如 SELECT C1, COUNT(C2) FROM TEST GROUP BY C1 FOR UPDATE;
带聚集函数的查询,如 SELECT MAX(C1)FROM TEST FOR UPDATE;
带 DISTINCT 的查询,如 SELECT DISTINCT C1 FROM TEST FOR UPDATEs;
对以下表类型的查询:外部表、物化视图、系统表和 HUGE 表;
WITH 子句,如 WITH TEST(C1) AS (SELECT C1 FROM T FOR UPDATE )SELECT * FROM TEST。
② 涉及 DBLINK 的 SELECT FOR UPDATE 查询支持外部链接的单表、多表查询,不支持外部链接表与模式内的表的连接查询;
③ 如果结果集中包含 LOB 对象,会再封锁 LOB 对象;
④ 支持多表连接的情况,会封锁涉及到的所有表的行数据;
⑤ 多表连接的时候,如果用 OF <选择列表>指定具体列,只会检测和封锁对应的表。
例如:SELECT C1 FROM TEST, TESTB FOR UPDATE OF TEST.C1 即使 TESTB 表类型不支持FOR UPDATE,上述语句还是可以成功;
⑥ DM 数据守护环境中,备库执行 SELECT FOR UPDATE 查询时,会直接忽略其中的FOR UPDATE 子句。
7. TOP子句
在DM中,可以使用TOP子句来筛选结果。
例 1 查询现价最贵的两种产品的编号和名称。
SELECT TOP 2 PRODUCTID,NAME FROM PRODUCTION.PRODUCT ORDER BY NOWPRICE DESC;
例 2 查询现价第二贵的产品的编号和名称。
SELECT TOP 1,1 PRODUCTID,NAME FROM PRODUCTION.PRODUCT ORDER BY NOWPRICE DESC;
例3 查询最新出版日期的70%的产品编号、名称和出版日期。
SELECT TOP 70 PERCENT WITH TIES PRODUCTID,NAME,PUBLISHTIME FROM PRODUCTION.PRODUCT ORDER BY PUBLISHTIME DESC;
- LIMIT限定条件
在DM中,可以使用限定条件对结果集做出筛选,支持LIMIT子句和ROW_LIMIT子句两种方式。
(1) LIMIT 子句
LIMIT 子句按顺序选取结果集中某条记录开始的 N 条记录。
注意:
一个查询表达式中不能同时包含 LIMIT 和 TOP 子句;
LIMIT 子句可用在 UPDATE 或 DELETE 操作之后,形式如“DELETE FROM T1 LIMIT 2;”。
例 1 查询前 2 条记录
SELECT PRODUCTID , NAME FROM PRODUCTION.PRODUCT LIMIT 2;
例 2 查询第 3,4 个登记的产品的编号和名称。
SELECT PRODUCTID, NAME FROM PRODUCTION.PRODUCT LIMIT 2 OFFSET 2;
例 3 查询前第 5,6,7 个登记的姓名。
SELECT PERSONID,NAME FROM PERSON.PERSON LIMIT 4,3;
(2) ROW_LIMIT 子句
ROW_LIMIT 子句用于指定查询结果中偏移的行数,或从指定偏移开始的百分比行数,以便更为灵活地获取查询结果。
使用说明
物化视图的查询定义中包含有 ROW_LIMIT 子句时,该物化视图不能增量刷新。
例 1 查询价格最便宜的 50%的商品
SELECT NAME, NOWPRICE FROM PRODUCTION.PRODUCT ORDER BY NOWPRICE FETCH FIRST 50 PERCENT ROWS ONLY;
例 2 查询价格第 3 便宜开始的 3 条记录
SELECT NAME, NOWPRICE FROM PRODUCTION.PRODUCT ORDER BY NOWPRICE OFFSET 2 ROWS FETCH FIRST 3 ROWS ONLY;
- PIVOT 和 UNPIVOT 子句
在 DM 中,可以使用 PIVOT 子句或 UNPIVOT 子句,将一组数据从行转换为列,或者从
列转换为行。
(1) PIVOT 子句
PIVOT 子句将一组数据从行转换为列。
使用说明
使用多个集函数时,必须为每个集函数指定别名;
不支持 COVAR_SAMP、COVAR_POP、COLLECT、CORR 和 REGR_XXX(除了REGR_COUNT)集函数;
<pivot_for_clause>或<exp_clause>中,针对多个<列名>或<表达式>,必须
使用小括号括起来;针对单个<列名>或<表达式>,使用或者不使用小括号均可;
<pivot_for_clause>中的列个数与<exp_clause>中的表达式个数应一致;
指定的<集函数>个数与<pivot_in_clause>中表达式个数的乘积不能超过2048;
指定 XML 时,结果集返回类型为 TEXT;
PIVOT 子句中未涉及的所有查询项,都将作为分组项。
创建测试表 SALES_ORDER 并插入数据。
CREATE TABLE SALES_ORDER (
SALESORDERID INT, //订单编号
SALESMAN VARCHAR(10), //销售员姓名
PRODUCT_NAME VARCHAR(10), //产品名称
AMOUNT DEC(10,2) //订单金额
);
//插入数据
INSERT INTO SALES_ORDER VALUES(1,‘李兰’,‘苹果’,860);
INSERT INTO SALES_ORDER VALUES(2,‘李兰’,‘苹果’,820);
INSERT INTO SALES_ORDER VALUES(3,‘李兰’,‘橘子’,1566);
INSERT INTO SALES_ORDER VALUES(4,‘李兰’,‘草莓’,3200);
INSERT INTO SALES_ORDER VALUES(5,‘李兰’,‘草莓’,2750);
INSERT INTO SALES_ORDER VALUES(6,‘王勇’,‘苹果’,630);
INSERT INTO SALES_ORDER VALUES(7,‘王勇’,‘苹果’,750);
INSERT INTO SALES_ORDER VALUES(8,‘王勇’,‘橘子’,1200);
INSERT INTO SALES_ORDER VALUES(9,‘王勇’,‘草莓’,2700);
INSERT INTO SALES_ORDER VALUES(10,‘王勇’,‘草莓’,3280);
INSERT INTO SALES_ORDER VALUES(11,‘孙晓萌’,‘橘子’,1350);
INSERT INTO SALES_ORDER VALUES(12,‘孙晓萌’,‘橘子’,1180);
INSERT INTO SALES_ORDER VALUES(13,‘孙晓萌’,‘草莓’,3300);
INSERT INTO SALES_ORDER VALUES(14,‘孙晓萌’,‘草莓’,3170);
查询 SALES_ORDER 表中数据。
SELECT * FROM SALES_ORDER;
例 1 使用 PIVOT 子句,将 PRODUCT_NAME 列中的 3 种产品所对应的行数据转换为列进行展示。
SELECT * FROM SALES_ORDER
PIVOT (
SUM(AMOUNT)
FOR PRODUCT_NAME
IN(‘苹果’,‘橘子’,‘草莓’)
);
PIVOT 子句中未提及的所有查询项都将作为分组项,因此上述语句的分组项为SALESORDERID 和 SALESMAN。
PIVOT 子句所在层级的 SELECT 语句的查询项必须为“*”,否则将报错。
例如,执行以下
语句将报错:
SELECT SALESMAN,PRODUCT_NAME,AMOUNT
FROM SALES_ORDER
PIVOT (
SUM(AMOUNT)
FOR PRODUCT_NAME
IN(‘苹果’,‘橘子’,‘草莓’)
);
第 7 行附近出现错误[-2111]:无效的列名[PRODUCT_NAME].
用户可以借助子查询来指定表或视图中的部分字段作为查询项。
例如利用子查询选择
SALESMAN、PRODUCT_NAME 和 AMOUNT 作为查询项。
SELECT *
FROM (SELECT SALESMAN,PRODUCT_NAME,AMOUNT FROM SALES_ORDER)
PIVOT (
SUM(AMOUNT)
FOR PRODUCT_NAME
IN(‘苹果’,‘橘子’,‘草莓’)
);
上述语句利用子查询选择SALESMAN、PRODUCT_NAME 和AMOUNT作为查询项,其中的分组项为SALESMAN,有利于统计各销售人员针对不同产品的销售总额。
例 2 可以在 IN 子句中为每个数据值指定别名,指定的别名将作为转换后各列的列名。
例如可以通过指定别名,去除列名中的单引号。
SELECT *
FROM (SELECT SALESMAN,PRODUCT_NAME,AMOUNT FROM SALES_ORDER)
PIVOT (
SUM(AMOUNT)
FOR PRODUCT_NAME
IN (‘苹果’ AS 苹果,‘橘子’ AS 橘子,‘草莓’ AS 草莓)
);
例 3 使用多个集函数,此时需要为每个集函数指定别名。
SELECT *
FROM (SELECT SALESMAN,PRODUCT_NAME,AMOUNT FROM SALES_ORDER)
PIVOT (
SUM(AMOUNT) AS 订单总额,
COUNT(AMOUNT) AS 订单数量
FOR PRODUCT_NAME
IN(‘苹果’ AS 苹果, ‘橘子’ AS 橘子)
);
例 4 FOR 子句中指定多列,此时需要在 IN 子句中同时指定多列的数据值。
SELECT *
FROM (SELECT SALESMAN,PRODUCT_NAME,AMOUNT FROM SALES_ORDER)
PIVOT (
SUM(AMOUNT)
FOR (SALESMAN,PRODUCT_NAME)
IN(
(‘李兰’,‘橘子’) AS 李兰_橘子总额,
(‘王勇’,‘橘子’) AS 王勇_橘子总额,
(‘孙晓萌’,‘橘子’) AS 孙晓萌_橘子总额)
);
例 5 指定 XML,使用 XML 格式输出数据,同时指定 ANY 关键字,表示选择PRODUCT_NAME 列中的全部产品。
SELECT *
FROM (SELECT SALESMAN,PRODUCT_NAME,AMOUNT FROM SALES_ORDER)
PIVOT XML (
SUM (AMOUNT)
FOR PRODUCT_NAME
IN (ANY)
);
例 6 指定 XML,使用 XML 格式输出数据,同时使用子查询语句选择 PRODUCT_NAME列中的产品。
SELECT *
FROM (SELECT SALESMAN,PRODUCT_NAME,AMOUNT FROM SALES_ORDER)
PIVOT XML (
SUM(AMOUNT)
FOR PRODUCT_NAME
IN(
SELECT PRODUCT_NAME
FROM SALES_ORDER
WHERE PRODUCT_NAME=‘苹果’ OR PRODUCT_NAME=‘橘子’)
);
(2) UNPIVOT 子句
UNPIVOT 子句将一组数据从列转换为行。
使用说明
<unpivot_val_col_lst> 、 <unpivot_for_clause> 或 <unpivot_in_clause>中,针对多个<表达式>、<列名>或<别名>,必须使用小括号括起来;针对单个<表达式>、<列名>或<别名>,使用或者不使用小括号均可;
<unpivot_val_col_lst>和<unpivot_for_clause>中的表达式个数保持一致;
<unpivot_for_clause>中的表达式个数与<unpivot_in_clause>中的 AS 项别名个数保持一致;
多个<unpivot_in_clause>之间指定的列数据类型要保持一致;
仅支持对单表、视图、DBLINK 进行 UNPIVOT 转换;
INI 参数 UNPIVOT_OPT_FLAG 可控制输出结果的顺序,UNPIVOT_OPT_FLAG 取值包含 1 时按照不包含在 UNPIVOT 中的列进行排序;
UNPIVOT 中自定义的列名不能为保留字;
<unpivot_in_clause_low>中指定的转换列个数不能超过 1000 个;
<unpivot_in_clause_low>中指定的转换列不能是 ROWID\TRXID 列;
UNPIVOT 不支持 ROLLUP、CUBE 以及 GROUPING SETS 查询,不能同时存在 PIVOT子句。
例 1 创建测试视图 PIVOT_SALES_ORDER_1。
CREATE VIEW PIVOT_SALES_ORDER_1 AS
SELECT *
FROM (SELECT SALESMAN,PRODUCT_NAME,AMOUNT FROM SALES_ORDER)
PIVOT (
SUM(AMOUNT)
FOR PRODUCT_NAME
IN(‘苹果’ AS 苹果,‘橘子’ AS 橘子,‘草莓’ AS 草莓)
);
查询 PIVOT_SALES_ORDER_1 视图中数据。
SELECT * FROM PIVOT_SALES_ORDER_1;
查询结果如下:
使用 UNPIVOT 子句,将苹果、橘子、草莓三列数据转换为行。
SELECT * FROM PIVOT_SALES_ORDER_1
UNPIVOT (
TOTAL_AMOUNT
FOR PRODUCT_NAME
IN(苹果,橘子,草莓)
);
可以看到,由于缺省不显示 NULL 值,因此以上结果集中并未包含孙晓萌对苹果的销售金额信息。用户可使用 INCLUDE NULLS 来指定结果集中包含 NULL 值。
SELECT * FROM PIVOT_SALES_ORDER_1
UNPIVOT INCLUDE NULLS (
TOTAL_AMOUNT
FOR PRODUCT_NAME
IN(苹果,橘子,草莓)
);
例 2 创建测试视图 PIVOT_SALES_ORDER_2。
CREATE VIEW PIVOT_SALES_ORDER_2 AS
SELECT *
FROM (SELECT SALESMAN,PRODUCT_NAME,AMOUNT FROM SALES_ORDER)
PIVOT (
SUM(AMOUNT) AS 金额,
COUNT(AMOUNT) AS 订单量
FOR PRODUCT_NAME
IN(‘苹果’ AS 苹果,‘橘子’ AS 橘子,‘草莓’ AS 草莓)
);
查询 PIVOT_SALES_ORDER_2 视图中数据。
SELECT * FROM PIVOT_SALES_ORDER_2;
使用 UNPIVOT 子句,将所有金额列和订单量列转换为行。
SELECT * FROM PIVOT_SALES_ORDER_2
UNPIVOT (
(SUM_AMOUNT,COUNT_AMOUNT)
FOR (PRODUCT_NAME_SUM,PRODUCT_NAME_COUNT)
IN(
(苹果_金额,苹果_订单量) AS (‘苹果销售额’,‘苹果订单量’),
(橘子_金额,橘子_订单量) AS (‘橘子销售额’,‘橘子订单量’),
(草莓_金额,草莓_订单量) AS (‘草莓销售额’,‘草莓订单量’)
)
);
UNPIVOT 子句缺省不显示 NULL 值,但仅当 SUM_AMOUNT 和 COUNT_AMOUNT 同时为 NULL 时才不显示,因此以上结果集中仍然包含孙晓萌对苹果的销售金额和订单量信息。