本专利文件内容的一部分包含受版权保护的材料。版权拥有者不反对任何人对此专利文件或专利内容部分按照它在专利商标局的专利文件或记录中所呈现式样进行的复制,但是保留除此以外的所有版权权利。
(2)背景技术
计算机——尤其是计算机数据库应用程序——被企业和其他机构用来监测和记录有关组织活动信息。通常,机构会有各式各样必须执行的处理过程和活动,并且这些过程和活动会经常性的重现。确实,对一个组织来说,在任何特定时间有众多处于不同完成阶段的活动的实例是很普遍的现象。例如,一个企业可能会根据从客户处收到的订单来出售货物。一个所关心的活动可能是完成那些顾客订货单;每个订货单代表该活动的一个单独的实例。在某个特定的时间,该企业也许有多个处于不同完成阶段的活动的实例(即,来自多个客户的多个订单)。在另一个例子中,一个金融机构可能根据顾客的申请来贷放资金。一个所关心的活动可能是要把贷款申请处理完成(即,批准或拒绝),每一个申请表示这种活动的一个独立的实例。在任何特定的时间,可能会有多个处于不同处理阶段的贷款申请实例。再如另外一个例子,一个负责发行许可证的政府部门,可能有多个处于不同处理阶段的许可申请。
为了监控一个活动的众多实例,很多组织把关于那些活动实例的信息存储在一个数据库程序中。特别地,可以针对每个活动实例创建一条记录或其它数据对象。然后,记录的一个单独字段或其它部分将被建立,以便保存对每个实例都通用的某种信息类型的值。用前面的一个例子进行说明,卖方企业可以为每个客户订单分别创建一条数据库记录。在每条记录中,独立的字段可包括收到订单的时间、收到订单的地点、订购的货物、发货时间等等。数据库程序的这种用法常常概念化为表。活动的每个实例占用表的一行(或元组)。多个实例公共的每一信息类型被单独赋予表中一列。
通过在数据库表中为某个活动的每个实例放置相关数据,使利用不同途径来分析这些数据成为可能。然而,随着越来越多记录的积累,数据库的有用性会降低。对于一个大型企业,譬如每天会收到几十万甚至数百万份订单的销售方,记录的数目会达到数十万,甚至数百万条。每次检索数据库时,就需要一定的时间去搜索磁盘驱动器或其他存储驱动器。同样的,当新建记录和更新现有记录时,每新建或更新一条记录都需要一些时间。随着记录数目的增长,寻找一条特定记录所需的时间越来越长。在一个拥有成百(或成千)用户和数十万(或数百万)条数据库记录的企业或组织机构中,访问数据库系统的等待时间将会很长,而且系统磁盘空间可能会用完。
图1-3提供了这个问题的更详细的说明,并且在首选实施例的详细描述中,提供了一个相关的例子。图1是一个流程图,假设了一个批发企业处理客户订货单的过程,这是一家依据客户订单来销售货物的企业。为了方便起见,从现在开始我们称之为“A企业”。在方框1中,A企业收到一个订货单,然后创建了相应的数据库记录;同时输入收到这个订单的时间。在方框2和3中,在产品订货数量和订货人所在城市的记录字段中输入更多的数据。在方框4中,判断是否接受此订货单。如果不接受,则在方框5中填写相应的记录字段,并记录拒绝时间。如果接受此订货单,则结果会被记录下来。如果此订货单被批准,则在方框6和7中将输入更多的信息。在方框8中装箱,则在另一个字段中记入装箱时间。在方框9和10中将输入更多的数据,例如,集装箱类型和货运方式。发货后,在方框11中将输入发货时间。
图2是一张数据库表,它描述A企业中订货单实例数据库的一部分。每个订单在一个独立的行中,并且每个列对应一个订单的一种数据。为了简单起见,图2仅仅显示了流程图1中所搜集的一部分信息对应的列。在这个例子中,某些字段包含NULL值,表示一个特定事件的值未知,因为在相关的订货单中,这个值是未公布。此数据库中一个典型的查询可能是“上周提交的订单中,金额在1000美元以上的尚未接受或拒绝的有哪些?”这样的查询可以通过对这个表进行SQL(结构化查询语言)查询来实现。
附录A显示了一段代码创建图2中的表的SQL代码的实现(“create tablePO_InstanceData”),以及用于更新图2的表中各行的存储过程(“createprocedure PO_PrimaryImport”)。此存储过程接受一个唯一地确定了与一个活动实例的一条记录的PONum变元(在这个例子中,就是一个特定的订货单)和用于表中每一列的参数。在开始更新或插入记录之前,存储过程的多个参数可以将调用所需的名称-值对累积在存储器中(基于应用程序收集数据时使用的事务逻辑)。由于锁定和操作数据库记录的处理过程所需要的额外系统开销,所以在一个命令中对记录进行越多的更新(或插入)操作,效率就越高。存储过程首先发出一条“update”语句,替换一条记录中值不是NULL的那些列。这时它假定表中存在一些关于订货单(PO)的数据。要调用函数“coalesce”,以返回第一个非空(Non-NULL)变元。如果没有任何记录被更新(@@rowcount=0),这就是第一条关于此订货单的信息,会插入一条带所有变元参数的记录(即使它们的值为空(NULL))。
当相对较少的用户或程序线程试图写入一个表,并且记录也比较少时,诸如附录A所示的存储过程是令人满意的。不幸的是,正如图3中所示,随着表中的记录越来越多,性能会随着时间不断降低。实线表示写入性能,或者说每秒能写入的记录数目,它快速下降到很低的水平。相反的,平均磁盘I/O队列长度(虚线)很快增长到超出可接受的限度。这种性能的下降,应归因于表大小的增长。当记录数目较小时,性能受数据库服务器处理事务的速度的限制,而这个速度又取决于服务器的中央处理单元的能力。随着时间的增加,记录数目也在增长(例如,越来越多的接收和处理过的订货单),性能迅速下降。例如,附录A中,存储过程中更新语句的第一次执行,会导致从磁盘中将表的一部分(图2)读入RAM(或者其他内存系统)。只要记录总数较小,服务器能够在系统内存中缓存所需的大部分或者全部数据。如果随后的更新需要操作早已缓存在系统内存中的记录,则服务器不需要再去读磁盘。然而,当记录的数目超过了内存的容量,每个操作都可能请求一个读磁盘的物理操作。根据所用的硬件,在磁盘被读取的时候,其它对于这张表的查询(或者更新)可能会被阻止。最终,对所有用户来说,反应时间慢到了不可接受的地步。如果要在这个表上执行更多复杂的数据操作,这个问题将更加严重。这些操作包括,在线分析处理(OLAP)和OLAP方块的建立。
(5)具体实施方式
本发明可以方便地与美国专利申请序列号。10/157,968中描述的方法、设备和系统结合使用。该专利申请的发明名称是“Support for Real-Time QueriesConcerning Current State,Data and History of a Process”,于2002年5月31日提交,其内容通过引用包括于此。
本发明的说明中将会参考到结构化查询语言(SQL)指令和其它数据分析特性,包括由华盛顿州雷蒙德的微软公司所提供的SQL SERVERTM 2000关系数据库管理系统(RDBMS)软件和相关的在线分析处理(OLAP)服务软件中的。尽管在此描述的是在实现本发明中实施例时可以使用的SQL指令的一些方面,但是对于本领域技术人员而言,一旦阅读了本发明提供的描述,则可用其他的指令、编程算法和过程实现本发明是显而易见的。对SQL SERVERTM 2000 RDBMS软件和相关的OLAP服务软件的简单说明可以从多种途径得到,包括KarenDelaney(2001微软出版社)的《Inside MicrosoftR SQL SERVERTM 2000》,以及可以从
http://www.microsoft.com/sql/techinfo/productdoc/2000/处得到的MicrosoftR SQL SERVERTM 2000 Books Online。本发明并非只限于使用SQL SERVERTM 2000 RDBMS软件及相关的OLAP服务软件来实现,它可以使用其它种类的RDBMS和OLAP软件来实现。
本发明说明中也将参考运行于服务器并且由一个或多个客户端访问的RDBMS软件(例如前述的SQL SERVERTM 2000软件)。这种配置是人们熟知的,例如在先前引入的美国专利申请10/157,968中有描述。然而,客户机/服务器配置只是实现本发明的方式中的一个例子。本发明也可以在其他物理系统配置中实现。
通过维护不同的表:对应于组织活动中的活跃实例数据的表、以及有限数目的非活跃实例的表,本发明可以解决上文所讨论的很多问题。例如,在很多组织机构中,最重要的活动是那些当前悬而未决的,或者最近刚刚完成的。据联系图1-3讨论的假想的A企业的例子,A企业的经理们最感兴趣的是依然在处理中的订货单,也就是那些仍然没有被送出去的货物。那些经理们同样感兴趣的是那些在相对较近时期里已完成的订货单(即,在最近几个月中货物已交货的订货单)。虽然A企业是为了描述本发明而建立的一个假想例子,但是在真实的企业中,仍在处理的实例或最近已完成实例是很常见的。例如,在很多企业中,大部分的送货投诉和大部分的费用收取问题都是在发货之后短时期内发生的。尽管出于某些目的也许需要更早些填具的订单数据,但是这些需要相对来说很少。类似地,很多其他类型的企业和组织最关心的是依然没有完成的活动的实例,以及一定数量的最近完成的活动实例。
因此,A企业在不同的数据库表中维护活跃的和最近已完成的订单数据。通过将表的内容限制在活跃的订单和最近才完成的订单,能保持较小的数据量。这样一来,当更新或以其它方式存取活跃实例数据表时,系统性能不会像图3中那样下降,而且存取已完成实例表时性能也不会下降,因为在此表中只插入记录,不会更新记录。和图3中的例子不同,整体性能随着时间的流逝也保持稳定。图4的方框图举例说明了这个概念。表10保存了涉及活跃订货单的数据记录。在这个例子中,如果订货单的货物依然没有送达客户,则此订货单是活跃的。组织的活跃活动实例在其它上下文环境下会有不同的定义。一旦一个订货单完成,该订货单的数据将被移动到表12。在此例中,当定购货物被送达客户时,该订货单被完成。如同活跃实例一样,一个组织的已完成实例在其它上下文环境下可有不同的定义。
每收到一个新订单,就在表10中建立一条记录。表10在图4中用方框形式表示,图5更详细地显示了表10中的一部分内容。与图2中的表类似,表10中一个记录(例如,行)对应一个订货单,每个字段(列)中的数据类型各不相同。在这个例子中,“PONum”是订货单编号,“City”是发出订货单的客户所在城市,“Quantity”是定购的货物数量。“ShipTime”是所定购的货物装运日期和时间。“DeliveryTime”是交货日期和时间。尚未装运的订单的ShipTime字段中是一个<NULL>条目。图5中的一些记录,显示了还未装箱的货物的订单(PONum 8680和8685-87)。当这些订货单的货物装运后,“ShipTime”字段将被更新。与图2中的表不同,表10中仅限于记录那些当前活跃的订货单数据,也就是那些货物尚未发出的订单。因此,每条记录的“DeliveryTime”字段是一个NULL条目。表10还有个“IsCompleted”标志的字段。IsCompleted的值为0时,表示对应的订货单还没有完成。在一些实施例中,IsCompleted是一个“system”标志,不显示给查询此表的用户。
当一个订货单完成后,该订货单记录被从活跃实例数据表10中删除,并且在已完成实例表12中为该订货单建立一条新的记录(图4)。这个新的记录是表10中所删除记录的复本,但是会用新数据覆盖DeliveryTime字段的NULL值,并且没有IsCompleted字段。图6详细的显示了表12的其中一部分。与图2和图5中的表类似,表12中一个记录对应一个已完成的订货单,不相同数据类型各有一个字段,包括前面提到的订货单号PONum、收到时间RecvTime、城市City、数量Quantity、发运时间ShipTime和交货时间DeliveryTime。在这个例子中我们定义在定购的货物发货时订货单完成,所以表12中DeliveryTime字段在每一条记录上都是非NULL的值。表12还有一个字段记录号“RecordID”。如下面将详细介绍的,表12中每增加一条已完成订货单的记录,就动态递增生成这个值。通过与图6中的PONum和RecordID字段进行比较可以看出,订货单完成的顺序,不一定会完全按照分配的订货单编号的顺序。因此,RecordID字段提供了一种机制,可以按照创建表12中的记录的次序生成索引。这确保了表的大小不会影响插入的性能,从而避免了随时间推移性能下降的问题。
因为表10中仅包括当前活跃的订货单的数据,所以表的大小始终比较小。尽管随着业务量的波动表的大小可能会有所起伏,但是不会无限增大。随着更多的订货单从活跃/未完成状态成转变成非活跃/已完成状态,已完成实例数据表12将会变大。但是,已完成实例数据表12的增长,比起包含了所有活跃和非活跃实例的单个数据表(如图2中的表)的增长,简直是不足挂怀。因为记录只是被插入表12,之后并不更新。所以不需要在每次存取表12时,搜索某一条记录。换言之,因为记录不用被更新,所以,表12中插入一条记录之前,不必寻找特定的记录。
附录B和C包含了一段用于创建和更新图4-6中的表的SQL代码的示例。附录B的第一条语句(“create table PO_Active_InstanceData”)创建了用于活跃实例的表10,并且建立PONum、RecvTime、City、Quantity、ShipTime、DeliveryTime和IsCompleted列。将PONum指定为主键。换句话说,表10中的每行都是由订货单标号即PONum来唯一地标识。类似地,下一条语句(“createtable PO_Completed_InstanceData”)创建了用于已完成实例的表12,并且建立PONum、RecvTime、City、Quantity、ShipTime、DeliveryTime和RecordID列。不过在表12中,RecordID被作为主键,它的值通过SQL“identity”属性自动递增获得。换句话说,随着向名为PO_Completed_InstanceData的表12中每增加一条新的记录,数据库服务器自动将前一个RecordID的值加1,然后将得到的值插入新增记录中。
下一条语句(“create procedure PO_PrimaryImport”)创建一个名为PO_PrimaryImport的存储过程,它被用于在表10中创建新记录或者更新现有的记录。存储过程PO_PrimaryImport有5个变元,对应于表10中一行上的列。例如,如果收到图5中的订货单8680,客户机将向数据库服务器发出下面的存储过程调用:
PO_PrimaryImport(8680,08/25/2003,17:19,Redmond,270,,,)
如果之前订货单8681的PONum、RecvTime、City和Qunantity的数据已经输入,下面的存储过程调用将把装运时间(ShipTime)更新成08/26/2003 0910:
PO_PrimaryImport(8681,,,,08/26/2003 0910,,)
为了更新订货单8682的记录以反映发货时间(DeliveyTime)为08/26/2003晚上12点整,并将订货单标记为已完成状态(IsCompleted=1),可发出下面的调用:
PO_PrimaryImport(8682,,,,08/26/2003 1200,1)
需要指出,操作人员将上述任何信息输入客户机时,不一定通过键入一个上述命令来完成。例如,用户可以通过一个图形用户界面来输入信息,在客户机/服务器上运行的一层或多层中间软件可以用正确的语法生成这个存储过程调用。再如,订单可能通过因特网自动接收,然后web服务器软件能生成必要的SQL命令。
存储过程PO_PrimaryImport接收这个存储过程调用中传递的值,然后把这些值分别赋给一个或多个本地变量@PONum、@RecvTime、@City、@Quantity、@ShipTime、@DeliveryTime和@IsCompleted。接着,存储过程试图通过“insert”语句将那些本地变量的值插入表PO_Active_InstanceData(表10)。然而,并不是将那些本地变量作为新记录插入表10,而是触发附录C中的触发器(“PO_CompletedTrigger”)。
参考附录C,在声明了本地变量@PONum和@IsCompleted之后,触发器把从“插入的”系统表中得到的值赋给这些变量。插入表是数据库服务器自动生成,并在RAM或其它系统存储器中临时存储那些在前面执行存储过程PO_PrimaryImport的“insert”语句时受到影响的行的副本。在这种情况下,插入表包含存储过程PO_PrimaryImport传递的变元的副本。换句话说,其中包含了用户当前试图插入或更新到表10中的值。
触发器首先查看被传递的IsCompleted位的值是否等于1,根据IsCompleted位可以判断,所传递的PONum值所对应的记录是完成的。如果IsCompleted位等于1,触发器就把已完成订货单记录的所有值插入到表12PO_Completed_InstanceData的新记录中。表12中新记录的PONum值是从插入表(“select inserted.PONum”)中得到的。函数“coalesce”用于获取表12中新记录的RecvTime、City、Quantity、ShipTime和DeliveryTime的值。特别地,(聚结)coalesce函数将从它的变元中返回第一个非NULL表达式。例如,“coalesce(inserted.RecvTime,po.RecvTime)”提供了表12中新记录的RecvTime字段的值。触发器首先去验查插入表中RecvTime值是否为非NULL。如果是,这个值就成为表12中新记录的RecvTime值。如果插入表中RecvTime值是NULL,那么触发器就从表10的某个记录中获取RecvTime的值,用户试图使用对存储过程PO_PrimaryImport的调用来插入或更新这个记录。代码“from inserted left join PO_Active_InstanceData po oninserted.PONum=po.PONum”可以保证coalesce函数有一个变元是Non-NULL(非空的)。准确地说,触发器的这部分代码载明,每个coalesce函数调用的变元值将从下面的集合中得到:这个集合包含(插入)“inserted”表中的所有行,外加O_Active_InstanceData表(表10)中的所有行,这两个表中PONum值是相同的。例如,如果调用存储过程PO_PrimaryImport来传递其所有变元的非NULL值(即,当订货单被第一次输入系统的时候,此订货单的货物已经发货),则表12中新记录的RecvTime值将从插入表中得到。但是,如果调用此存储过程PO_PrimaryImport是为了更新表10中已经存在的记录,并且此记录中已经存在RecvTime值(即,在PO_PrimaryImport存储过程调用中不传递RecvTime值),那么表12中新记录的值将从表10的现存记录中得到。
在获得RecvTime的值之后,触发器用类似的方法获得表12中新记录的City、Quantity、ShipTime和DeliveryTime字段的值。正如前面所讨论的,服务器自动生成RecordID字段的值。然后,触发器删除表10中已完成的订货单记录(“delete from PO_Active_InstanceData where PONum=@PONum”)。此时,该触发器终止(“return”)。
如果在对触发了触发器的PO_PrimaryImport存储过程的调用中传递的IsCompleted值是0,那么触发器不在表12中建立新记录,而是设法更新由PO_PrimaryImport存储过程调用中所指定的表10中的记录(“updatePO_Active_InstanceData”)。正如在表12中新建记录的触发器一样,coalesce函数被用来为表10中所更新的记录提供一个值,这个值可从插入表,或者表10现存记录中得到。但是,在这种情况下,coalesce函数的变元值由代码“fromPO_Active_InstanceData po join inserted on po.PONum=inserted.PONum”提供。准确地说,触发器的这部分代码指明,每个coalesce函数调用的变元值,将从下面的集合中得到:这个集合包含PO_Active_InstanceData表(表10)和插入表中的所有行,这些行应具有相同的PONum值。
如果存储过程PO_PrimaryImport(附录B)被调用以在表10中增加一个未完成的新记录(也就是,插入一条尚未发货的订货单的新记录),则触发器中的“update PO_Active_InstanceData”代码,并没有更新什么值。在此情况下,在表10中不存在PONum值和插入表的PONum值相等的记录,从而在表10中没有记录需要更新。如果表10中没有记录要更新,或者没有记录要插入表12,那么触发器将通过系统函数@@rowcount来检测。准确的说,如果前面的update语句没有影响到任何行,那么函数@@rowcount返回0值。如果函数@@rowcount返回0,那么触发器的一部分代码“insertPO_Active_InstanceData select * from inserted”将用根据(插入)“inserted”表中得到的值在表10中插入一条新记录。
在本发明的另一个实施例中,已完成实例数据表的数据量是有限的。如上所示,该表(图4中的表12)的增长不及表2这样的表那么在意。然而表4也会随着时间不断增长。即使表中没有记录被更新(也就是,记录只是被插入),该表也会最终变得太大,以至于超过系统磁盘容量,或者对于此表中数据的查询,所需要的时间长到无法接受。如前所示,A企业的经理已经确定,只有对近期内完成的订货单才需要已完成订货数据。但是,删除表12中的记录可能很耗时。在很多软件环境中,必须逐行删除;在每个记录上必须获得行锁,然后行被标识成已删除。实际上,删除一行和插入或更新一行所需的时间完全一样。
因此,如图7所示,为已完成实例数据建立了多个表。在此实施例中,附录B和附录C中的代码像前述那样操作,它从表10中删除已完成订货单记录,并在表12中建立相应的新记录。然而,不允许表12无限制的增长。在一定时间后(例如,一个月),表12将被重命名为唯一的分区名,且不会再有更多的记录被添加到这个已改名的表中。此后,会新建一个空的表12,它使用已改名的表从前的名称,即PO_Complete_InstanceData。从这时起,触发器在该新表中插入记录。又过了一个月(或者其它预先指定的时间间隔)之后,这个表也被重命名,然后再创建一个表12。当一个已改名的表被保留了指定的时间段之后(例如,六个月),整个表被删除。与删除单个记录不同,删除整个表非常快。在一个实施例中,使用SQL命令“drop table”去删除表。当删除一个已完成的实例数据表时,该表中的数据不一定会丢失。例如,在调用删除表“drop table”的函数之前,将表中数据传输到磁带或其它类型的存储媒体中存档。在其它的实施例中,不是在固定的间隔后建立新的表12,而是在表12达到一定的大小时,建立新的表12。
因此,活跃实例和已完成实例表中的所有数据,都可以方便的查看和查询(也就是,单次查询不一定会涉及到每个独立的表)。活跃和已完成实例表(或者所需要的部分表的小组)能被组合成一个分区视图。在至少一个实施例中,可以使用SQL语句“union all select * ...”将多个表组合起来。每次在删除一个已完成实例数据表(或者,每创建一个新的已完成实例数据表时)时,都可以重新创建这个由表组合而成的视图。
在本发明的另一方面,活跃的和已完成的实例的表中的数据被进一步处理,以便提供更多的分析数据。举例来说,A企业可能希望对当前活跃的订货单数据以及当前已完成订货单数据作联合分析。例如,A企业希望为这些组合的数据生成一个或多个OLAP方块。此外,尽管A企业是为了说明本发明而假想的企业,但是真实的组织也需要生成反映该组织活动中活跃的和已完成的实例的OLAP方块。
从图8可以看出,在至少一个实施例中的一个数据处理流程。它是对活跃和已完成实例数据的组合OLAP分析的处理。定期地执行存储过程(“BeginDataProcessing”)(例如,每天晚上)。该过程首先建立活跃实例数据表(表10)的一个副本。因为此表比较小,所以该副本能很快建立。然后该副本中的数据被传送到数据转化服务器(DTS)(未示出),以便被放置到一个星型模式中,然后把这些活跃实例数据完全处理成OLAP方块30。存储过程BeginDataProcessing也从一个递增窗口中获取一部分已完成实例数据。特别的,存储过程BeginDataProcessing每次获取已完成实例数据时,数据库服务器将保存最后获取的记录的RecordID值。如前所述,这个值是在创建记录时,由服务器以递增的方式赋值的。通过参照以前运行过程BeginDataProcessing的时候存储的最后获取的活跃实例数据记录的RecordID值,此次运行存储过程时,仅获取上次运行之后建立的记录。这个递增的窗口作为一个特殊视图来实现,该视图建立在分区视图之上,这个分区视图包含多个用于活跃和已完成实例数据的表/分区块。这样一来,该递增窗口能包含多个分区的数据。例如,如果过程BeginDataProcessing每周执行一次,那么在上次执行存储过程BeginDataProcessing后可能有新的已完成实例数据表建立,而且可能需要处理多个已完成实例数据表的数据。在至少一个实施例中,存储过程BeginDataProcessing同时获得活跃实例数据表的副本和已完成实例数据表的记录的副本。否则,在过程BeginDataProcessing复制之后,但在获取已完成实例数据表记录之前,订货单可能被从活跃实例数据表中移除。如果发生这种情况,那么相同的的订货单将会被处理两次,从而破坏了数据分析的准确性。
存储过程BeginDataProcessing把自前次BeginDataProcessing执行之后建立的增量已完成实例数据记录传送给DTS。然后DTS将该递增数据放入一个已包含了从上一次已完成实例数据处理来的数据的星型模式。然后,已完成实例数据的星型模式(它现在包含最近的已完成实例数据记录的递增数据)被用于更新已完成实例OLAP方块32。类似于已完成实例星型模式,OLAP方块32包含了前面几次会话中处理过的记录的信息。然后OLAP方块30和OLAP方块32被组合成一个虚拟OLAP方块34。随着时间的推移,与OLAP方块32中包含其信息的已完成记录数会变得越来越大。然而,通过递增地处理已完成实例数据,并且将处理结果与之前处理过的已完成实例数据进行组合,能在相当短的时间内生成OLAP方块32(以及虚拟OLAP方块34)。换言之,可以避免重复处理已完成实例数据。
虚拟OLAP方块34向用户提供了一个业务的“快照”,它包含了历史的和进行中的(即,活跃的)的订货单的信息。可以安排在晚上或其它较闲的时间内运行处理方块30-34的数据转换服务(DTS)软件包。
尽管本发明的说明使用的是一个假想的企业,但是应注意,该发明并不局限于某一特定类型的企业、组织或活动。事实上,本发明并不限于以已完成实例数据的使用时间为依据来保留已完成实例数据的实现,别的组织为了能快速存取非活跃实例数据,可能使用一些其它标准,而不是维护最近月份所完成的订货单的数据。仅仅作为一个例子,一个调查公司可能希望快速地操作若干批次数据,但是可能很少操作其它批次的数据。因此,虽然介绍了运用该发明的具体例子,但是本领域技术人员将明白,上述系统和技术的很多变化形式、排列将落入所附权利要求书中阐明的本发明的精神和范围。这些和其它改变属于所附属权利要求所定义的本发明的范围。
附录A
create table PO_InstanceData
(
PONum int primary key,
RecvTime datetime null,
City nvarchar(50)null,
Quantity int null,
ShipTime datetime null,
DeliveryTime datetime null
)
go
create procedure PO_PrimaryImport
(
@PONum int,
@RecvTime datetime=null,
@City nvarchar(50)=null,
@Quantity int=null,
@ShipTime datetime=null,
@DeliveryTime datetime=null
)
as
begin
update PO_InstanceData
set
RecvTime=coalesce(@RecvTime,RecvTime),
City=coalesce(@City,City),
Quantity=coalesce(@Quantity,Quantity),
ShipTime=coalesce(@ShipTime,ShipTime),
DeliveryTime=coalesce(@DeliveryTime,DeliveryTime)
where PONum=@PONum
if @@rowcount=0
insert PO_InstanceData values
(@PONum,@RecvTime,@City,@Quantity,@ShipTime,@DeliveryTime)
end
附录B
create table PO_Active_InstanceData
(
PONum int primary key,
RecvTime datetime null,
City nvarchar(50) null,
Quantity int null,
ShipTime datetime null,
DeliveryTime datetime null,
IsCompleted bit
)
create table PO_Completed_InstanceData
(
RecordID int primary key identity,
PONum int,
RecvTime datetime null,
City nvarchar(50) null,
Quantity int null,
ShipTime datetime null,
DeliveryTime datetime null
)
go
create procedure PO_PrimaryImport
(
@PONum int,
@RecvTime datetime=null,
@City nvarchar(50)=null,
@Quantity int=null,
@ShipTime datetime=null,
@DeliveryTime datetime=null,
@IsCompleted bit=0
)
as
insert PO_Active_InstanceData values(
@PONum,
@RecvTime,
@City,
@Quantity,
@ShipTime,
@DeliveryTime,
@IsCompleted)
go
附录C
create trigger PO_CompletedTrigger on PO_Active_InstanceData
instead of insert
as
begin
declare @PONum int
declare @IsCompleted bit
select @PONum=PONum,@IsCompleted=IsCompleted from
inserted
if (@IsCompleted=1)
begin
insert PO_Completed_InstanceData
(PONum,RecvTime,City,Quantity,ShipTime,DeliveryTime)
select
inserted.PONum,
coalesce(inserted.RecvTime,po.RecvTime),
coalesce(inserted.City,po.City),
coalesce(inserted.Quantity,po.Quantity),
coalesce(inserted.ShipTime,po.ShipTime),
coalesce(inserted.DeliveryTime,po.DeliveryTime)
from inserted left join PO_Active_InstanceData po on
inserted.PONum=po.PONum
delete from PO_Active_InstanceData where
PONum=@PONum
return
end
update PO_Active_InstanceData
set
RecvTime=coalesce(inserted.RecvTime,po.RecvTime),
City=coalesce(inserted.City,po.City),
Quantity=coalesce(inserted.Quantity,po.Quantity),
ShipTime=coalesce(inserted.ShipTime,po.ShipTime),
DeliveryTime=coalesce(inserted.DeliveryTime,po.DeliveryTi
me)
from PO_Active_InstanceData po join inserted on
po.PONum=inserted.PONum
if @@rowcount=0
insert PO_Active_InstanceData select * from inserted
end
go