技术开发 频道

使用DB2 UDB OLAP函数

    如何使用日历表简化查询

    我从 [article on Pivot Tables] 中摘出了这个例子。首先,让我们创建一个表,并插入一些数据:

CREATE TABLE BUSINESS_TRIP(EMPLOYEE_ID INT NOT NULL, DATE_FROM DATE NOT NULL, DATE_TO DATE NOT NULL); INSERT INTO BUSINESS_TRIP VALUES (1, DATE('01/06/2003'), DATE('01/10/2003')), (1, DATE('01/13/2003'), DATE('01/17/2003')), (1, DATE('01/20/2003'), DATE('01/24/2003')), (1, DATE('01/27/2003'), DATE('01/31/2003')), (2, DATE('01/07/2003'), DATE('01/08/2003')), (3, DATE('01/08/2003'), DATE('01/09/2003'));

    假设有一个简单的任务:“选择 2003 年 1 月份没有雇员出差的所有日子”,这时日历表 DATE_SEQ 就很好用了。

SELECT SOME_DATE AS NOBODY_ON_TRIP FROM DATE_SEQ WHERE SOME_DATE BETWEEN DATE('01/01/2003') AND DATE('01/31/2003') AND NOT EXISTS(SELECT * FROM BUSINESS_TRIP WHERE SOME_DATE BETWEEN DATE_FROM AND DATE_TO); NOBODY_ON_TRIP -------------- 01/01/2003 01/02/2003 01/03/2003 01/04/2003 01/05/2003 01/11/2003 01/12/2003 01/18/2003 01/19/2003 01/25/2003 01/26/2003 11 record(s) selected.

    这个查询非常简单。在[article on Pivot Tables]中讨论了一些肯定是更复杂的替代方案。

    假设有一个类似的任务:“选择 2003 年 1 月份有两名以上雇员在出差的所有日子”,同样,这里日历表 DATE_SEQ 也提供了一个非常容易的方法:

SELECT SOME_DATE AS THREE_OR_MORE_ON_TRIP FROM DATE_SEQ WHERE SOME_DATE BETWEEN DATE('01/01/2003') AND DATE('01/31/2003') AND (SELECT COUNT(*) FROM BUSINESS_TRIP WHERE SOME_DATE BETWEEN DATE_FROM AND DATE_TO) > 2; THREE_OR_MORE_ON_TRIP ------------------- 01/08/2003

    同样,如果不能创建辅助表,我们就可以使用表表达式:

SELECT SOME_DATE AS THREE_OR_MORE_ON_TRIP FROM (SELECT DATE('01/01/2003') + ROW_NUMBER() OVER() DAYS AS SOME_DATE FROM SYSCAT.TABLES) AS DATE_SEQ WHERE SOME_DATE BETWEEN DATE('01/01/2003') AND DATE('01/31/2003') AND (SELECT COUNT(*) FROM BUSINESS_TRIP WHERE SOME_DATE BETWEEN DATE_FROM AND DATE_TO) > 2;

    使用顺序表将两条记录布置到一行上

    假设该表的结构和数据如下:  

CREATE TABLE VEHICLE_ACCIDENT( ACCIDENT_ID INT NOT NULL, TAG_NUMBER CHAR(10) , TAG_STATE CHAR(2) ); INSERT INTO VEHICLE_ACCIDENT VALUES(1,'123456','IL'), (1,'234567','IL'),(1,'34567TT','WI');

    (为了简单起见,这里省略了其他列)。注意,在一起事故中可能牵涉到不止两辆车。这就要求将两条记录布置到一行上,像这样(当牵涉到 3 辆车时):

    TAG_NUMBER_1 TAG_STATE_1 TAG_NUMBER_2 TAG_STATE_2
    ------------ ----------- ------------ -----------
    123456IL234567IL
    3456TTWI   

    通过使用 ROW_NUMBER() ,这一点很容易实现:

WITH VEHICLE_ACCIDENT_RN(ACCIDENT_ID, ROWNUM, TAG_NUMBER, TAG_STATE) AS (SELECT ACCIDENT_ID, ROW_NUMBER() OVER() AS ROWNUM, TAG_NUMBER, TAG_STATE FROM VEHICLE_ACCIDENT) SELECT LEFT_SIDE.TAG_NUMBER AS TAG_NUMBER_1, LEFT_SIDE.TAG_STATE AS TAG_STATE_1, RIGHT_SIDE.TAG_NUMBER AS TAG_NUMBER_2, RIGHT_SIDE.TAG_STATE AS TAG_STATE_2 FROM (SELECT L.*, (L.ROWNUM+1)/2 AS PAGENUM FROM VEHICLE_ACCIDENT_RN L WHERE MOD(ROWNUM,2)=1)AS LEFT_SIDE LEFT OUTER JOIN (SELECT R.*, (R.ROWNUM+1)/2 AS PAGENUM FROM VEHICLE_ACCIDENT_RN R WHERE MOD(ROWNUM,2)=0)AS RIGHT_SIDE ON LEFT_SIDE.PAGENUM = RIGHT_SIDE.PAGENUM WHERE LEFT_SIDE.ACCIDENT_ID=1 AND (RIGHT_SIDE.ACCIDENT_ID=1 OR RIGHT_SIDE.ACCIDENT_ID IS NULL)

    不管事故涉及的车辆是奇数还是偶数,该查询都给出了正确的结果。可以随意添加记录并进行检验。同样,如上一章所述,也可以通过一些其他的方法来解决这个问题。通过使用 ROW_NUMBER() ,我们可以得到一个很简单的解决方案,这个方案可以快捷地开发出来,并且易于理解。

0
相关文章