使用 OLAP 函数的一些实用技巧
在线分析处理(online analytical processing,OLAP)函数非常灵活,也很强大。通过使用这些函数,您可以为一些问题找到简单的解决方案,而这些问题本来要么是要迭代一个或者多个游标,要么是要进行递归。在其他某些情况下,编写查询时,使用 OLAP 函数或辅助表比起不使用它们来要容易得多。
本文没有对 OLAP 函数作什么描述,而是描述了实际生活中的一些情况,在这些情况中,往往是通过使用 OLAP 函数得出了简单的解决方案。
使用连续数或日期生成辅助表
辅助表不包含用户的数据。相反,这些表用于简化查询的编写。我们将使用两个辅助表:
xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">- 顺序表,即连续整数的列表,从 1 开始,以某个最大数结束。
- 日历表,即介于开始日期和结束日期之间的连续日期的列表。
本章中,我们将学习如何使用 OLAP 函数填充辅助表。
xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">注意:Joe Celko 撰写的“SQL for Smarties”一书对辅助表作了详细
xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">让我们创建并填充一个顺序表。使用一个 OLAP 函数 ROW_NUMBER() 为结果集中的各行提供连续数(consecutive number),像这样:
SELECT ROW_NUMBER() OVER(), TABNAME FROM SYSCAT.TABLES WHERE TABSCHEMA='DB2ADMIN' xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">1TABNAME xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">------------------------------------------- xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">1 CONSECUTIVE_NUMS xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2 DATES xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">3 EXPLAIN_ARGUMENT xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">4 EXPLAIN_INSTANCE xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">5 EXPLAIN_OBJECT xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">6 EXPLAIN_OPERATOR xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">7 EXPLAIN_PREDICATE xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">8 EXPLAIN_STATEMENT xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">9 EXPLAIN_STREAM xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">10 SALES_DETAIL xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">11 SALES_DETAIL_CLS xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">11 record(s) selected. xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
注意,即使没有被选中的列,也会提供连续数。例如,让我们使用从 1 开始的连续数来填充一个表。方法如下:
CREATE TABLE NUMBER_SEQ(NUM INT NOT NULL); xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">INSERT INTO NUMBER_SEQ SELECT ROW_NUMBER() OVER() FROM xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">SYSCAT.COLUMNS;
|
从 1 开始的连续数将被插入到表 NUMBER_SEQ 中,在系统视图 SYSCAT.COLUMNS 中,每个数字对应一行(我选择了 SYSCAT.COLUMNS,是因为它出现在每个数据库中,并且总是有 1,000 多行。您可以使用任何表,只要这个表有足够多(但不要太多)的记录)。在 NUMBER_SEQ 中会有 SYSCAT.COLUMNS 表中那么多的行:
SELECT MIN(NUM) AS MIN_NUM, MAX(NUM) AS MAX_NUM, COUNT(*) AS NUM_REC FROM NUMBER_SEQ MIN_NUM MAX_NUM NUM_REC ----------- ----------- ----------- 1 3197 3197 1 record(s) selected.
|
使用连续日期来填充一个日历表很容易:
CREATE TABLE DATE_SEQ(SOME_DATE DATE NOT NULL); xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">INSERT INTO DATE_SEQ SELECT DATE('01/01/2003') + (ROW_NUMBER() xmlns:dw="http://www.ibm.com/developerworks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> OVER() - 1) DAYS FROM SYSCAT.COLUMNS;
|
我们已经看到了如何使用 OLAP 函数 ROW_NUMBER() 来创建和填充辅助表。显然,有两种方法可以完成这一任务。例如,我们可以使用递归或者在一个循环中插入记录。在这种解决方案中,使用 ROW_NUMBER 的最大好处是简化了编程。
在接下来的三章中,我们将使用 NUMBER_SEQ 和 DATE_SEQ 这两个辅助表来简化某些本来比较复杂的查询。
使用顺序表打印发票
假设我们需要存储某杂货店一条收银线上的所有销售额。还需要能够打印任何一笔买卖的发票,像这样:
ITEM_NAME PRICE_PER_ITEM ------------------------------ ------------------------NESCAFE CLASSIC +6.49000000000000E+000 ENGLISH BAGELS 6-PACK +1.49000000000000E+000 ENGLISH BAGELS 6-PACK +1.49000000000000E+000
|
由于某些原因,我们选择不在数据库中存储重复的记录。也就是说,我们希望只存储一条记录 ('ENGLISH BAGELS 6-PACK', 1.49, 2) ,而不是两条记录 ('ENGLISH BAGELS 6-PACK', 1.49) 。
不存储重复行通常可以带来更多方便。因此,我们应该使用下面这样的表:
CREATE TABLE SALE_ITEM(SALE_ID INT NOT NULL,ITEM_NAME VARCHAR(30) NOT NULL,ITEM_QUANTITY SMALLINT NOT NULL,PRICE_PER_ITEM FLOAT NOT NULL);INSERT INTO SALE_ITEM VALUES(1, 'NESCAFE CLASSIC', 1, 6.49),(1, 'ENGLISH BAGELS 6-PACK', 2, 1.49),(1, 'BABY CARROTS', 3, 0.99);
|
我们需要编写一个查询,该查询的输出应该是这样的(实际上就是打印一张发票):
ITEM_NAME PRICE_PER_ITEM ------------------------------ ------------------------ NESCAFE CLASSIC +6.49000000000000E+000 ENGLISH BAGELS 6-PACK +1.49000000000000E+000 ENGLISH BAGELS 6-PACK +1.49000000000000E+000 BABY CARROTS +9.90000000000000E-001 BABY CARROTS +9.90000000000000E-001 BABY CARROTS +9.90000000000000E-001
|
下面是一个非常简单的查询,这个查询可以实现上述功能:
相关文章
广告赞助
Copyright © 2006-2007
中国建站网. All Rights Reserved .
合作联系: QQ: 8856499 黔ICP备07001966号