通用固定长度编码格式的字符串查找算法的实现

 
 

字符串的查找是数据库应用中必不可少的操作,而且每种数据库产品(ORACLE、DB2、SYBASE、MS SQL SERVER、MYSQL等等)也都提供了对应的字符串处理函数,比如DB2的LOCATE函数。

但在实际的工作中,还是会遇到一些特殊情况的处理,这使得直接使用字符串查找函数,得到的结果可能是错误的,比如本文中提到的固定长度编码格式的字符串的查找。值得注意的是,本文提出的算法可以稍加修改即移植到其它关系数据库系统或者前端开发工具中。

在实际数据库应用系统中,会经常遇到有些数据表中的一些字段,实际上是采用了某些固定格式的编码规则,比如在本人工作单位中的OLTP数据库中,有一个出口流水表TB_OUTLISTGW中的ROADCOMB字段、ROADSSTARTSTATION字段、ROADSSTARTSTATION字段中都是经过固定长度编码格式的数据,ROADCOMB记录了在广东省高速公路上行驶的车辆所经过的所有高速公路的组合,采用16进制编码,每两位表示一条高速公路的16进制编码,比如11代表10进制的17,即广惠高速公路。

举个例子来说,要统计哪些流水是经过了广惠高速公路(实际上需求比这复杂得多)。大家都会给出以下的SQL 语句(DB2格式)

SELECT *
FROMDEVELOP.TB_OUTLISTGW
WHERELOCATE(ROADCOMB,’11’)>0
FETCH FIRST 100ROW ONLY
WITH UR;

但实际上,这条语句是有一定问题的,ROADCOMB是每两位的16进制数据代表了一条路段,查找的时候需要每两个字符跟目标路段匹配一次,而不是每个字符+后面的字符跟目标字符串逐次进行匹配,本人采取的是以下的做法,建立了一个固定长度编码格式的字符串匹配通用函数,大家可以用其它关系数据库系统的SQL语法格式来翻译过去,这样就可以在其它数据库系统使用了。以下是笔者用万能数据库查询分析器的中文版本《DB 查询分析器》来创建并调用 这个通用的固定长度编码格式的字符串查找函数的过程。(具体方法详见我的博文《DB 查询分析器 6.03 方便地创建DB2自定义函数》   )

 


DROP FUNCTION DEVELOP.F_LOCATE_FIXED
$$


---通用的固定长度编码格式的字符串查找函数

CREATE FUNCTION DEVELOP.F_LOCATE_FIXED(IN V_SRC VARCHAR(4096),IN V_DES VARCHAR(4096))
RETURNS INTEGER
LANGUAGE SQL
DETERMINISTIC 
NO EXTERNAL ACTION
CONTAINS SQL
BEGIN ATOMIC
DECLARE v_resultINTEGERDEFAULT 0;
DECLARE str_roadVARCHAR(4096); 
DECLARE v_len_srcINTEGER;
DECLARE v_len_desINTEGER;
DECLARE v_pos_srcINTEGER DEFAULT 1;
SET v_len_des=LENGTH(TRIM(V_DES));
SET v_len_src=LENGTH(TRIM(V_SRC));
SET v_result=0;
AUTHLOOP:
WHILE v_pos_src+v_len_src<=v_len_des DO
SET str_road=SUBSTR(V_DES,v_pos_src,v_len_src); 

IF ( str_road=V_SRC ) THEN
SET v_result=v_pos_src;  --函数返回匹配的实际物理位置
SET v_result=v_result/v_len_src+1;  --函数返回匹配的逻辑位置,即第几个子串位置;这一条语句如果注释掉,函数将返回匹配的实际物理位置
LEAVE AUTHLOOP;
ELSE
SET v_pos_src=v_pos_src+v_len_src; 
END IF;  
END WHILE;

RETURN v_result;
END
$$

values  DEVELOP.F_LOCATE_FIXED('11','4F0A0B0D231154533F01')
$$

values  DEVELOP.F_LOCATE_FIXED('11','01100110011001100110011001100110')
$$

 
SELECT *
FROMDEVELOP.TB_OUTLISTGW
WHERE DEVELOP. F_LOCATE_FIXED ('11',ROADCOMB)>0
FETCH FIRST 100ROW ONLY
WITH UR;
$$

 

查看字符串编码 Java 查看字符串编码格式_万能数据库查询分析器


图1   SQL 语句执行前





查看字符串编码 Java 查看字符串编码格式_万能数据库查询分析器_02


图2   SQL 语句执行后(一)





查看字符串编码 Java 查看字符串编码格式_查看字符串编码 Java_03


图3   SQL 语句执行后(二) values  DEVELOP.F_LOCATE_FIXED('11','4F0A0B0D231154533F01')的返回结果






查看字符串编码 Java 查看字符串编码格式_字符串查找算法_04


图4   SQL 语句执行后(三) values  DEVELOP.F_LOCATE_FIXED('11','01100110011001100110011001100110')的返回结果

在字符串'01100110011001100110011001100110'中查找子串'11',关系数据库系统正常匹配会返回1;但实际情况字符串是2位一组,按照某种编码规则来编码,这种情况下进行固定2位长度进行匹配则会失败,应该返回0 。values DEVELOP.F_LOCATE_FIXED('11','01100110011001100110011001100110')也确实是返回了0。


 





总结:  如果字据库表中的字符串类型的字段查找中要涉及循环查找的话,就必然会用到函数的设计。给大家一个小问题来思考一下,如果要实现的功能是查找出出口流水表TB_OUTLISTGW中ROADCOMB(经过的高速公路列表)、ROADSSTARTSTATION(入口站列表)、ROADESTARTSTATION(出口站列表)中经过了特定调整公路的特定入口站和特定的高速公路出口站的通行记录,那又该如何实现呢?

每一条通行记录所经过的路段、该路段的入口站、该路段的出口站被依次记录在ROADCOMB(经过的高速公路列表)、ROADSSTARTSTATION(入口站列表,4位16进制编码)、ROADESTARTSTATION(出口站列表,4位16进制编码)这三个字段中。










 附录一  “万能数据库查询分析器”的简介


中国本土程序员马根峰推出的个人作品----万能数据库查询分析器,中文版本《DB 查询分析器》、英文版本《DB Query Analyzer》。它具有强大的功能、友好的操作界面、良好的操作性、跨越各种数据库平台乃至于EXCEL和文本文件。

你可以通过它  查询ODBC数据源(包括世面上所有的数据库、TXT/CSV文件、EXCEL文件)的数据。 你可以同时执行多条DML语句乃至存贮过程,结果会以你设定的表格、文本框、文件来返回;  从数据库导出千万条数据时,效率与DBMS没有什么区别; 具有强大的 SQL “执行计划”功能,你只要将“工具-à选项”窗口中的选项“SQL执行计划连接自动恢复”设置为“选中”状态,那么即使在“SQL执行计划”期间数据库服务器宕过机,只要在“SQL执行计划”的时刻数据库服务器是处理启动状态,那么“SQL执行计划”都会被执行;  6.03版本已经完全兼容任何Microsoft的Windows操作系统系列,包括Windows 10、Windows 8、Windows 7、Vista、Windows XP、Windows 2000等等,可以直接在Windows操作系统上运行,而不需要更改任何操作系统的设置或者配置。