技术开发 频道

使用DB2 UDB OLAP函数

    使用 ROW_NUMBER() 为客人分配房间

    让我们考虑一个简单的问题。假设有两个表:一个是宾馆可用房间的列表,一个是刚到的宾馆客人的列表。我们需要将可用的房间分配给刚到的客人,那么如果有空房间的话,应该尽量使每个客人得到一个房间。为了解决这样的问题,通常需要打开两个游标,一个是用于房间的游标,一个是用于客人的游标,然后迭代这两个游标,直到其中一个游标或者两个游标同时到达结尾处。下面是这个表的定义和一些样本数据: 

CREATE TABLE ROOM( ROOM_ID INT NOT NULL PRIMARY KEY, SMOKING CHAR(1) NOT NULL CHECK(SMOKING IN ('N','Y'))); INSERT INTO ROOM VALUES (121,'Y'),(139,'N'),(142,'N'),(201,'Y'),(202,'N'); CREATE TABLE GUEST( GUEST_ID INT NOT NULL PRIMARY KEY, SMOKER CHAR(1) NOT NULL CHECK(SMOKER IN ('N','Y'))); INSERT INTO GUEST VALUES(321, 'N'),(17,'Y'),(57,'Y'),(91,'Y'), (2,'N'),(444,'N'); CREATE TABLE GUEST_ASSIGNMENT( GUEST_ID INT NOT NULL PRIMARY KEY, ROOM_ID INT NOT NULL UNIQUE, FOREIGN KEY(GUEST_ID) REFERENCES GUEST(GUEST_ID), FOREIGN KEY(ROOM_ID) REFERENCES ROOM(ROOM_ID));

    如果使用 OLAP 函数 ROW_NUMBER() ,就不需要打开两个游标并迭代房间和客人。相反,我们可以简单地联结这两个表,并在房间与客人之间取得 1 对 1 的对应关系。为了理解其工作原理,让我们首先看看这个选择查询及其输出:

SELECT ROOM_NUMBER, GUEST_NUMBER, ROOM_ID, GUEST_ID FROM (SELECT ROW_NUMBER() OVER(ORDER BY ROOM_ID) AS ROOM_NUMBER, ROOM_ID FROM ROOM) AS R JOIN (SELECT ROW_NUMBER() OVER(ORDER BY GUEST_ID) AS GUEST_NUMBER, GUEST_ID FROM GUEST) AS G ON ROOM_NUMBER=GUEST_NUMBER ROOM_NUMBERGUEST_NUMBERROOM_IDGUEST_ID -------------------- -------------------- 111212 2213917 3314257 4420191 55202321

    这个例子查询将 ROOM 表中的最多一条记录与 GUEST 表中的最多一条记录相联结。注意,您可以不像我那样指定排序(OVER(ORDER BY GUEST_ID)),而是宣称排序不重要(OVER()),甚至请求使用随机排序(OVER(ORDER BY RAND()))。在这种情况下,一个客人得不到一个房间,因为没有足够的空房间。可以随意添加记录到 ROOM 表中,以检验该查询在其他情况下(例如有客人那么多的房间,或者没有客人那么多的房间)的工作情况。

    如果理解了联结的工作原理,填充 GUEST_ASSIGNMENT 表就比较容易了:

INSERT INTO GUEST_ASSIGNMENT SELECT GUEST_ID, ROOM_ID FROM (SELECT ROW_NUMBER() OVER(ORDER BY ROOM_ID) AS ROOM_NUMBER, ROOM_ID FROM ROOM) AS R JOIN (SELECT ROW_NUMBER() OVER(ORDER BY GUEST_ID) AS GUEST_NUMBER, GUEST_ID FROM GUEST) AS G ON ROOM_NUMBER=GUEST_NUMBER

    我们已经看到,在这种情况下使用 ROW_NUMBER() 函数可以为我们的开发节省很多力气。我们不必打开两个游标并迭代它们。

    使用 ROW_NUMBER() OVER(PARTITION ... ) 将不抽烟的客人分配到“无烟”房间

    前一章的示例过于简单。这里让我们更接近现实一点。让我们确保吸烟的客人住进允许吸烟的房间,而不吸烟的客人则住进无烟房间。下面的查询就实现了这一点: 

SELECT ROOM_NUMBER, GUEST_NUMBER, SMOKER, SMOKING, ROOM_ID, GUEST_ID FROM (SELECT ROW_NUMBER() OVER(PARTITION BY SMOKING ORDER BY ROOM_ID) AS ROOM_NUMBER, ROOM_ID, SMOKING FROM ROOM) AS R JOIN (SELECT ROW_NUMBER() OVER(PARTITION BY SMOKER ORDER BY GUEST_ID) AS GUEST_NUMBER, GUEST_ID, SMOKER FROM GUEST) AS G ON ROOM_NUMBER=GUEST_NUMBER AND SMOKER=SMOKING ROOM_NUMBERGUEST_NUMBERSMOKER SMOKING ROOM_IDGUEST_ID -------------------- -------------------- ------ ------- 11 NN1392 22 NN142321 33 NN202444 11 YY12117 22 YY20157

    同样,如果理解了如何联结 GUEST 和 ROOM 表中的记录,就可以通过一条简单的 INSERT 语句填充 GUEST_ASSIGNMENT 表。这种方法显然比迭代客人上的游标和房间上的游标要容易得多。

0
相关文章