简化sql计算系列之记录拆分

       数据库应用开发中,经常会遇到一些比较复杂的SQL式计算,比如记录拆分,将按分隔符分隔的一条记录拆分成多条记录。SQL在实现时由于数据库间的差异,会遇到语法支持不足、嵌套多层等问题。而集算器具有丰富的类库,可以编写直观分步的脚本,完成这类计算要简单许多,下面通过一个例子来看一下集算器的实现方式。

 

       应用程序将用户一次登陆后的所有操作代码按逗号分隔,以一条记录存储到数据库用户操作表user_op中,该表部分数据如下:

LOGTIME             USERID OPID

2014/1/3 11:10:12  100001    a,d,h

2014/1/3 9:23:12    100002    a,e,g,p

2014/1/3 10:35:11  100003    a,r,n

      

       现需要将逗号分隔的OPID拆分成多行,如第一条记录拆分后应为:

LOGTIME             USERID OPID

2014/1/3 11:10:12  100001    a

2014/1/3 11:10:12  100001    d

2014/1/3 11:10:12  100001    h

 

       SQL在实现这类运算时需要借助递归查询实现,对于递归查询支持不好的数据库实现起来异常困难,而对递归查询支持不错的Oracle实现也并不简单,比如下面的SQL实现语句:

SELECT logtime,userid,REGEXP_SUBSTR(opid,'[^,]+',1,rn) opid
FROM user_op,(SELECT LEVEL rn FROM DUAL
CONNECT BY LEVEL<=(SELECT MAX(length(trim(translate(opid,replace(opid,','),' '))))+1 FROM user_op))
WHERE REGEXP_SUBSTR(opid,'[^,]+',1,rn) IS NOT NULL

 

或者

select logtime,userid,regexp_substr(opid,'[^,]+',1,level) opid
from user_op
connect by level <= length(opid)-length(regexp_replace(opid,'[^,]+',''))
and rowid= prior rowid
and prior dbms_random.value is not null

       

从以上的实现中可以看出SQL实现的复杂性,下面看一下集算器的实现代码:



 

   其中:

       A1=esProc.query("SELECT LOGTIME,USERID,OPID FROM USER_OP")

从数据库中查询user_op表数据,部分查询结果如下:



 

         A2= A1.create()

 

         根据A1的序表创建新序表,并复制A1的结构,用于存储最终结果集。结果如下:



 

         A3=A1.(OPID.array().(A2.record([A1.LOGTIME,A1.USERID,~])))

 

         循环A1序表,拆分OPID字段值,转为转为序列,并将拆分后结果写回A2结果集。计算后的A2结果如下:



 

         可以看到在集算器中通过这样简单的三行代码就完成了拆分记录的计算。另外,集算器可被报表工具或java程序调用,调用的方法也和普通数据库相似,使用它提供的JDBC接口即可向java主程序返回ResultSet形式的计算结果,具体方法可参考相关文档。

猜你喜欢

转载自datamachine.iteye.com/blog/2199833