上个星期接了个有关member数据质量处理的小项目,要求是根据会员的联系人名字,公司名,联系电话等信息,从DW中筛选出合法的会员来。

 

对于联系人名字筛选,要求是:

只能是包含1-4个中文汉字,名字可以有空格。不能包括字母数字已经标点符号等。

SQL> select * from v$nls_parameters where PARAMETER='NLS_CHARACTERSET';
 
PARAMETER                                                        VALUE
----------------------------------------------------------------
NLS_CHARACTERSET                                                 US7ASCII

 

解决方案:

 

中文汉字是双字节存储的,而字母数字以及标点符号等都是单字节的,所以,通过判断联系人里面每个字符是单字节还是多字节的,就知道它是否符合条件了。

 

同事已经写了一个统计有多少个汉字的函数,那么我写sql就方便多了。

create or replace function fun_get_chinese_c_cnt
(
 p_string          IN VARCHAR2
)
RETURN NUMBER IS
/*********************************************************************
*模块:
*频率:
*功能:判断字符串中汉字的个数
*作者:wzy
*时间:2009-03-24
*备注:
*********************************************************************/
     l_result               NUMBER;
     l_us7            NUMBER(3);      --US7ASCII编码下字符串长度
     l_str_us7          VARCHAR2(256) := p_string;  --ZHS16GBK编码下的keyword
     l_analyze_code1    VARCHAR2(3);    --双字节字符的第一字节的10进制编码
     i                INT;            --循环控制
BEGIN
     l_us7 := LENGTH(p_string);
     l_result:=0;
     i:=1;
     ------逐个字符分析KeyWord------
     WHILE i <= l_us7 LOOP
           ------获取字符的十进制编码------
           l_analyze_code1:=ascii(substr(l_str_us7,i,1));
           ------字符类型判断------
           IF(l_analyze_code1<128)THEN --单字节的情形
              i:= i+1;
           ELSE--双字节的情形
              i:=i+2;
              l_result:=l_result+1;
           END IF;
           --l_result:=l_result+1;
     END LOOP;--keyword分析完毕
     RETURN(l_result);
END ;

那么我现在只需要用 汉字的个数*2 = 字段值的长度 这个条件做筛选就OK了,再考虑空格情况,这样就需要用这个条件之前把空格替换掉就行了,sql如下:

SELECT *
FROM cntmp.membertocompanytemp
WHERE --check first_name
(
            fun_get_chinese_c_cnt(REPLACE(TRIM(first_name), ' ', '')) * 2 = length(REPLACE(TRIM(first_name), ' ', ''))
            AND length(REPLACE(TRIM(first_name), ' ', '')) >= 2 --1个中文字
            AND length(REPLACE(TRIM(first_name), ' ', '')) <= 8   --4个中文字  
)

 

总 结:

1.   每个中文汉字占用两个字节,用dump()函数可以看到具体的ascii的值

2.   一般的而言,简体字的编码都大于128,而繁体字的第二个字节编码值小于128,所以如下语句都会查询到结果:

SELECT job_title, DUMP(job_title)

FROM cntmp.membertocompanytemp

WHERE regexp_like(job_title, '[a-zA-Z0-9]')

--job_title LIKE '%a%'

AND fun_get_chinese_c_cnt(REPLACE(TRIM(job_title), ' ', '')) * 2 = length(REPLACE(TRIM(job_title), ' ', ''));

我们刚好可以利用这一点筛选出包含繁体字的数据。

当然,也有极少数繁体字两个字节的编码都大于128的。

3.   双字节的字符也包含中文符号,日文等等。