- 遍历字符串
- 字符串文字中包含引号
- 计算字符在字符串中出现的次数
- 从字符串中删除不需要的字符
- 将字符和数字数据分离
- 判别字符串是不是字母数字型的
- 提取名字的大写首字母缩写
- 按字符串中部分内容排序
- 安字符串中的数值排序
- 根据表中的行创建一个分隔列表
- 将分隔数据转换为多值in列表
- 按字母顺序排列字符串
- 判别可作为数值的字符串
- 提取第n个分隔的子串
- 分解IP地址
1.遍历字符串
遍历字符串在数据库中的开销是很大的,因为数据库中没有循环操作。
如果真的要这么做,可以参考:
select substr(e.ename,iter.pos,1) as c from
(select ename from emp where ename='king') e,
(select id as pos from t10) iter
where iter.pos<=length(e.ename);
Note: t10,t100都是一种临时表,其id是从1开始逐渐递增的
2.字符串文字中包含引号
解决方案:通常出现在数据插入或者是条件查询的时候,
包含引号的字符串作为值或条件使用,参考如下:
select ename from emp where ename='Allen''s Khlid';
其中条件的值实际是 Allen's Khlid 。
Note:整个语句中单引号是成对出现的,最外层的单引号仅仅表示条件或值是字符串,
内层两个相邻单引号表示实际数据的一个单引号,如果在SQL中,两个单引号内没有任何值,
表示null值。例如: select ename from emp where ename='';
这个等价于 select ename from emp where ename is null;
3.计算字符在字符串中出现的次数
解决方案:用replace函数将制定字符串替换掉,计算与替换之前的长度差距来确定
select (length(ename)-length(replace(ename,'AC','')))/length('AC') as times from emp;
4.从字符串中删除不需要的字符
db2: select ename,replace(translate(ename,'AC','ac'),'ac','') as newone from emp;
mysql,sqlserver: select ename,replace(ename,'AC','') as newone from emp;
oracle,postgreSQL : select ename,replace(translate(ename,'AC','##'),'#','') as new one from emp;
Note:多用于进行批量操作,当然replace函数在where子句运行之前运行
5.将字符串和数字数据分离
db2: select replace(translate(data,'00000000000','0123456789'),'0','') ename,
cast(
replace(translate(lower(data),repeat('z',26),'abcdefghighklmnopqrstuvwxyz'),
'z','') as integer) sal from
(select ename||cast(sal as char(4)) data from emp) x;
oracle: select replace(translate(data,'0123456789','00000000000'),'0') ename,
to_number(
replace(translate(lower(data),'abcdefghighklmnopqrstuvwxyz',rpad('z',26,'z')),
'z')) sal from
(select ename||sal data from emp) x;
postgreSQL: select replace(translate(data,'00000000000','0123456789'),'0','') as ename,
cast(
replace(translate(lower(data),rpad('z',26,'z'),'abcdefghighklmnopqrstuvwxyz'),
'z','') as integer) as sal from
(select ename||sal as data from emp) x;
Note:看上去很麻烦的样子,确实很麻烦
6.判断字符串是不是字母数字型的
db2: select ename from emp where translate(lower(ename),repeat('a',36),'0123456789abcdefghijklmnopqrstuvwxyz') = repeat('a',length(ename));
mysql: select ename from emp where ename regexp '[0-9a-zA-Z]' >0;
oracle,postgreSQL : select ename from emp where translate(lower(ename),'0123456789abcdefghijklmnopqrstuvwxyz',rpad('a',36,'a'))=rpad('a',length(ename),'a');
sqlserver: 不支持translate函数,必须判断每一行中包含非数字字母值,回去看第1个就好
7.提取姓名的大写首字母缩写
可以使用substring函数或者是translate函数进行操作,每种数据库基本上问题不大
8.按字符串中的部分内容排序
这个就是按照字符串的子串进行排序
mysql : select ename from emp order by substr(ename,length(ename)-1,2);
9.按字符串中的数值排序
先将字符串中的数值转换成单独的一列,然后再按照这一列的值进行排序
10.根据表中的行创建一个分隔列表
db2 : with x (deptno,cnt,list,empno,len) as (
select deptno,count(*) over (partition by deptno),cast(ename as varchar(100)),empno,1 from emp union all
select x.deptno,x.cnt,x.list ||','|| e.ename,e.empno,x.len+1 from emp e,x
where e.deptno=x.deptno and e.empno>x.empno
) select deptno,list from x where len=cnt;
mysql: select deptno,group_concat(ename order by empno separator , ',') as emps from emp group by deptno;
oracle: select deptno,ltrim(sys_connect_by_path(ename,','),',') emps from
(selelct deptno,ename,row_number() over (partition by deptno order by empno) rn, count(*) over (partition by deptno) cnt from emp) where level=cnt
start with rn=1 connect by prior deptno=deptno and prior rn=rn-1;
postgreSQL和sqlserver也有,但是不再继续整理
11. 将分隔数据转换为多值IN列表
这个处理的是where子句中条件的数据类型不匹配问题
例如:select ename from emp where empno in ('1,9,16');
这种情况下是要想办法将后面的字符串转化成跟empno一致的数据类型才可以工作
出现几率非常小
12.按字母顺序排列字符串
db2: select ename, max(case when pos=1 then c else '' end )
|| max(case when pos=2 then c else '' end )
|| max(case when pos=3 then c else '' end )
|| max(case when pos=4 then c else '' end )
|| max(case when pos=5 then c else '' end )
|| max(case when pos=6 then c else '' end )
from (
select e.ename,cast(substr(e.ename,iter.pos,1) as varchar(100)) c,
cast(row_number() over (partition by e.name order by substr(e.ename,iter.pos,1)) as integer) pos
from emp e,
(select case(row_number() over ( ) as integer) pos from emp) iter
where iter.pos<=length(e.ename)
) x group by ename;
mysql: select ename,group_concat(c order by c separator '') from (
select ename,substr(ename,iter.pos,1) c from emp a,
(select id pos from t10) iter
where iter.pos<=length(a.ename)
) x group by ename;
oracle : select old_name,new_name from (
select old_name, replace(sys_connect_by_path(c, ' '),' ') new_name from (
select e.ename,old_name,row_number() over (partition by e.ename order by substr(e.ename,iter.pos,1) c from emp e,
(select rownum pos from emp) iter
where iter.pos<=length(e.ename) order by 1 ) x
start with rn=1 connect by prior rn=rn-1 and prior old_name=old_name
) where length(old_name) = length(new_name)
)
sqlserver: select ename, max(case when pos=1 then c else '' end )
+ max(case when pos=2 then c else '' end )
+ max(case when pos=3 then c else '' end )
+ max(case when pos=4 then c else '' end )
+ max(case when pos=5 then c else '' end )
+ max(case when pos=6 then c else '' end )
from (
select e.ename , substring(e.ename,iter.pos,1) as c , row_number() over (
partition by e.ename order by substring(e.ename,iter.pos,1)) as pos
from emp e,
(select row_number() over (order by ename) as pos from emp) iter
where iter.pos<=len(e.ename)
) x group by ename;
13.判别可作为数值的字符串
基本操作时使用函数replace和translate,然后做进一步处理
14.提取第n个分隔的子串
db2: select substr(c,2,locate(',',c,2)-2) from (
select pos,name,substr(name,pos) c,row_number() over (partition by name order by length(substr(name,pos)) desc) rn from (
select ',' ||csv.name|| ',' as name,cast(iter.pos as integer) as pos from v csv,
(select row_number() over () pos from t100) iter
where iter.pos<=length(csv.name)+2
) x where length(substr(name,pos))>1 and substr(substr(name,pos),1,1)=','
) y where rn=2;
mysql: select name from ( select iter.pos,substring_index(substring_index(src.name,',',iter.pos),',',-1) name from v src,
(select id pos from t10) iter where iter.pos<=length(src.name)-length(replace(src.name,',',''))) x where pos=2;
oracle: select sub from (
select iter.pos,src.name,substr(src.name,instr(src.name,',',1,iter.pos)+1,
instr(src.name,',',1,iter.pos+1)-
instr(src.name,',',1,iter.pos)-1 ) sub
from (select ','||name||',' as name from v) src,
(select rownum pos from emp) iter
where iter.pos<length(src.name)-length(replace(src.name,','))
) where pos=2;
15分解IP地址
这种分解过程可以从前面的实例中找到
Note:使用字符串操作要注意函数的运行时在where子句之前运行还是之后运行,当在where子句之前运行的时候,记录的行数直接决定了字符串操作的快慢。