【sql查询与优化】5.使用字符串
注:以下所有sql案例均取自oracle查询优化改写技巧与案例丛书。 1.遍历字符串 有时候要求把字符串拆分成单个字符,如: create or replace view v asselect 天天向上 as 汉字, TTXS as 首拼 from dual; 为了核对表中保存的“首拼”是否正确,需要把字符串拆分
注:以下所有sql案例均取自"oracle查询优化改写技巧与案例"丛书。1.遍历字符串
有时候要求把字符串拆分成单个字符,如:
create or replace view v as select '天天向上' as 汉字, 'TTXS' as 首拼 from dual;
为了核对表中保存的“首拼”是否正确,需要把字符串拆分成下面的样式:
汉字 首拼
———— ————
天 T
天 T
向 X
上 S
拆分之前,我们先看一个connect by子句:
select level from dual connect by level<br> level<br> --------<br> 1<br> 2<br> 3<br> 4<br> <br> 其中,connect by是树形查询中的一个子句,后面level是一个“伪列”,表示树形查询中的级别层次,通过level <br> 那么我们就可以通过connect by子句把v循环显示四行,并给出定位标识level:<br> select v.汉字,v.首拼,level from v connect by level <br> 汉字 首拼 LEVEL<br> ------------------------ -------- ----------<br> 天天向上 TTXS 1<br> 天天向上 TTXS 2<br> 天天向上 TTXS 3<br> 天天向上 TTXS 4<br> <br> 根据上面的数据,就可以通过函数substr(v.汉字,level,?)得到需要的结果:<br> <pre code_snippet_id="1692086" snippet_file_name="blog_20160522_3_8881054" name="code" class="sql">select v.汉字, v.首拼, level, substr(v.汉字,level,1) as 汉字拆分, substr(v.首拼,level,1) as 首拼拆分, 'substr(''' || v.汉字 || ''',' || level || ',1)' as fun from v connect by level<br> 汉字 首拼 LEVEL 汉字拆分 首拼拆分 FUN<br> ------------------------ -------- ---------- -------- -------- ----------<br> 天天向上 TTXS 1 天 T substr('天天向上',1,1)<br> <br> 天天向上 TTXS 2 天 T substr('天天向上',2,1)<br> <br> 天天向上 TTXS 3 向 X substr('天天向上',3,1)<br> <br> 天天向上 TTXS 4 上 S substr('天天向上',4,1)<br> <br> 可以看到我们是利用level的值将字符串进行拆分的,最后的fun可以看出来。<br> <br> 注:<br> substr(string,start,length)<br> string - 指定的要截取的字符串。<br> start - 必需,规定在字符串的何处开始。正数 - 在字符串的指定位置开始,负数 - 在从字符串结尾的指定位置开始,0 - 在字符串中的第一个字符处开始。<br> length - 可选,指定要截取的字符串长度,缺省时返回字符表达式的值结束前的全部字符。<br> <br> <br> 2.字符串文字包含引号<br> 常常有人写SQL时不知道在字符串内的单引号怎么写,其实只要把一个单引号换成两个单引号表示就可以。<br> <pre code_snippet_id="1692086" snippet_file_name="blog_20160522_4_8182942" name="code" class="sql">select 'g''day mate' qmarks from dual union all select 'beavers''teeth' from dual union all select '''' from dual;
QMARKS
--------------------------
g'day mate
beavers'teeth
'
注:
(Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;
Union All:对两个结果集进行并集操作,包括重复行,不进行排序;
Intersect:对两个结果集进行交集操作,不包括重复行,同时进行默认规则的排序;
Minus:对两个结果集进行差操作,不包括重复行,同时进行默认规则的排序。
可以在最后一个结果集中指定Order by子句改变排序方式。)
另外,Oracle 10g开始引入了q-quote特性,允许按照指定的规则,也就是Q或者q开头(如果是national character literals,则是N或n放在Q或q之前),字符串前后使用界定符“'”,使用规则很简单。
(1)q-quote 界定符可以是除了TAB、空格、回车外的任何字节或多字节字符。
(2)界定符可以是[]、{}、、(),而且必须成对出现。
上面的例子用q-quote的写法就比较明确了。
select q'[g'day mate]' qmarks from dual union all select q'[beavers' teeth]' from dual union all select q'[']' from dual;
QMARKS
----------------------------
g'day mate
beavers' teeth
'
3.计算字符在字符串中出现的次数
字符串'CLARK,KING,MILLER'被逗号分隔成了三个子串,现要求用SQL计算其中的子串个数,对于这种问题,我们一般计算其中的逗号个数后加1就可以。
下面来看怎么计算逗号的个数。
为了方便引用,首先建立一个view:
create or replace view v as select 'CLARK,KING,MILLER' as str from dual;
SQL> select str from v;
STR
----------------------------------
CLARK,KING,MILLER
Oracle 11g给出了新函数regexp_count,我们可以直接引用。
select regexp_count(str,',')+1 as cnt from v;
若没有regexp_count的版本怎么办?我们用regexp_replace迂回求值即可。
select length(regexp_replace(str,'[^,]'))+1 as cnt from v;
CNT
----------
3
注:regexp_replace是正则表达式函数,是使用正则表达式来替换str
参数:
第一个是输入的字符串
第二个是正则表达式
第三个是替换的字符
还可以使用前面介绍的translate:
select length(translate(str,',' || str,','))+1 as cnt from v;
CNT
----------
3
注:translate(string,from_str,to_str)
执行时,translate依次检查string中的每个字符是否在from_str中存在,如果不存在,那么这个string中的字符直接返回,如果存在,translate会记下这个字符在from_str中的位置,然后用to_str的同样位置的字符代替string中的这个字符作业返回结果。
如果分隔符有一个以上,那就要把计算出来的长度再除以分隔符长度。
create or replace view v as select '10$#CLARK$#MANAGER' as str from dual;
正确写法:
select length(translate(str,'$#' || str,'$#'))/length('$#')+1 as cnt from v;
CNT
----------
3
而用regexp_count就可以不用考虑长度:
regexp_count(str,"\$#")+1 as cnt from v;
可能有人注意到,第二个参数里多了一个“\”,这是因为“$”是通配符,需要用“\”转义。
4.从字符串中删除不需要的字符
create or replace view employes as select 'CLARK' as ename from dual union all select 'KING' as ename from dual union all select 'MILLER' as ename from dual;
若员工姓名中有元字母(AEIOU),现在要求把这些元音字母去掉,很多人都用如下语句:
select ename, replace(translate(ename,'AEIOU','aaaaa'),'a','') stripped1 from employes;
ENAME STRIPPED1
------------ ------------------------------------------------
CLARK CLRK
KING KNG
MILLER MLLR
这里先把元音字母替换成'a',然后把'a'去掉。
其实用前面介绍的translate的一个用法就可以,根本不需要嵌套:
select ename,translate(ename,'1AEIOU','1') stripped1 from employes;
ENAME STRIPPED1
------------ ------------------------------------------------
CLARK CLRK
KING KNG
MILLER MLLR
是不是要方便的多?
当然,也可以用更简单的正则函数regexp_replace,直接把[]内列举的字符替换为空:
select ename, regexp_replace(ename,'[AEIOU]') as stripped1 from employes;
ENAME STRIPPED1
------------ ------------------------------------------------
CLARK CLRK
KING KNG
MILLER MLLR
5.将字符和数字数据分离
建立测试用表如下:
select * from dept2;
--------------
管理部门3322
销售部门3321
后勤部门3320
金融部门3319
data其实是部门名称和部门编号的连接,现在希望将部门名称和部门编号分别分开,并命名为dname和deptno。
可以使用如下正则表达式:
select regexp_replace(data,'[0-9]','') dname, regexp_replace(data,'[^0-9]','') deptno from dept2;
DNAME DEPTNO
---------- ----------
管理部门 3322
销售部门 3321
后勤部门 3320
金融部门 3319
在上面出现的正则表达式中,[0-9]是一种表示方式,代表[0123456789],还可以表示为[[:digit:]]。那么把这些数据替换之后剩下的就是那些字母了。而[^0-9]中的“^”表示否定的意思,代表[0-9]的外集,也就是除[0123456789]外的所有字符。要注意“^”的位置:在方括号内,所有的字符之前。
如果不习惯使用正则表达式,还可以使用translate
select translate(data,'a0123456789','a') dname, translate(data,'0123456789' || data,'0123456789') deptno from dept2;
DNAME DEPTNO
---------- ----------
管理部门 3322
销售部门 3321
后勤部门 3320
金融部门 3319
6.查询只包含字母或数字型的数据
示例数据如下:
create or replace view v as select '123' as data from dual union all select 'abc' from dual union all select '123abc' from dual union all select 'abc123' from dual union all select 'a1b2c3' from dual union all select 'a1b2c3#' from dual union all select '3$' from dual union all select 'a 2' from dual;
SQL> select * from v;
DATA
--------------
123
abc
123abc
abc123
a1b2c3
a1b2c3#
3$
a 2
上述语句中,有些数据包含了空格/逗号/$等字符。现在要求返回其中只有字母及数据的行。
如果直接按需求字面意思来写,可以用正则表达式。
SQL> select data from v where regexp_like(data,'^[0-9a-zA-Z]+$');
DATA
--------------
123
abc
123abc
abc123
a1b2c3
regexp_like 就相当于普通的like。
regexp_like(data,'[ABC]')就相当于(like '%A%'or like '%B%'or like '%C%');而regexp_like(data,'[0-9a-zA-Z]+')就相当于(like '%数字%'or like '%小写字母%'or like '%大写字母%')。
“^”不在括号里时表示字符串开始,而“$”表示字母串的结束。例如regexp_like(data,'A')代表普通的like '%A%';而regexp_like(data,'^A')代表普通的like 'A%',即没有了前模糊查询;regexp_like(data,'A$')代表普通的like '%A',即没有了后模糊查询;而regexp_like(data,'^A$')代表普通的like 'A',即精确查询。
另一个概念是“+”与“*”。“+”表示匹配前面的自表达式一次或多次;“*”表示匹配前面的子表达式零次或多次。
7.提取姓名的大写首字母缩写
本例要求返回下面view中的大写字母,中间加“.”,显示为“M.H”:
create or replace view v as select 'Micheal Hartstein' as ai from dual;
SQL> select * from v;
AI
----------------------------------
Micheal Hartstein
我们可以利用regexp_replace的分组替换功能:
select regexp_replace(v.ai,'([[:upper:]])(.*)([[:upper:]])(.*)','\1.\3') as sx from v;
SX
------
M.H
括号()将子表达式分组为一个替换单元、量词单元或后向引用单元。
在这个查询中,我们用()把字符串分成了四个组,其中第1、3组中是大写字母,然后通过后向引用('\1.\3')就分别取到了两个组的大写字母,并在中间增加了字符“.”。
即是,将字符串拆分为(1)大写([[:upper:]]) (2)小写(.*) (3)大写([[:upper:]]) (4)小写(.*)四个部分,取其(1)(3)。
也可以使用前面介绍的translate函数。
第一步,先把字符串转换为小写,这样就得到了translate所需的参数2
select ai,lower(ai) as a2 from v;
AI A2
--------------------- ----------------------
Micheal Hartstein micheal hartstein
第二步,把空格替换为“.”,小写字母(上面得到的a2)置空就是我们需要的数据。
select translate(ai,' '||a2,'.')as a3 from (select ai,lower(ai) as a2 from v);
A3
------
M.H
8.按字符串中的数值排序
首先建立如下view,要求按照其中的数字排序:
create or replace view v as select 'ACCOUNTING 10 NEW YORK' as data from dual union all select 'OPERTIONS 40 BOSTON' as data from dual union all select 'RESEARCH 20 DALLAS' as data from dual union all select 'SALES 30 NEW CHICAGO' as data from dual;
SQL> select * from v;
DATA
--------------------------------------------
ACCOUNTING 10 NEW YORK
OPERTIONS 40 BOSTON
RESEARCH 20 DALLAS
SALES 30 NEW CHICAGO
我们可以用正则表达式替换非数字字符,语句如下:
select data,to_number(regexp_replace(data,'[^0-9]','')) as deptno from v order by 2;
DATA DEPTNO
----------------------------- ----------
ACCOUNTING 10 NEW YORK 10
RESEARCH 20 DALLAS 20
SALES 30 NEW CHICAGO 30
OPERTIONS 40 BOSTON 40
也可以使用translate函数,直接替换掉非数字字符:
select data, to_number(translate(data,'0123456789'||data,'0123456789')) as deptno from v order by 2;
DATA DEPTNO
----------------------------- ----------
ACCOUNTING 10 NEW YORK 10
RESEARCH 20 DALLAS 20
SALES 30 NEW CHICAGO 30
OPERTIONS 40 BOSTON 40
9.提取第n个分隔的子串
首先建立如下view,要求按照其中的数字排序:
create or replace view v as select 'CLARK,KING,MILLER' as name from dual union all select 'ADAMS,FORD,JONES,SCOTT,SMITH' as name from dual;
SQL> select * from v;
NAME
--------------------------------------
CLARK,KING,MILLER
ADAMS,FORD,JONES,SCOTT,SMITH
上面各行中的字符串用逗号分隔,现在要求将其中的子串中的KING与FORD取出来。
没有正则表达式之前需要找到逗号的对应位置,然后对字符串进行截取:
select name, 第二个逗号后的位置, 第三个逗号的位置, 长度, substr(name,第二个逗号后的位置,长度) as 子串 from (select name, instr(src.name, ',', 1, 2) + 1 as 第二个逗号后的位置, instr(src.name, ',', 1, (2+1)) as 第三个逗号的位置, instr(src.name, ',', 1, (2+1)) - instr(src.name, ',', 1, 2) - 1 as 长度 from(select ',' || name || ',' as name from v)src )x;
NAME 第二个逗号后的位置 第三个逗号的位置 长度 子串
------------------------------ ------------------ ------------------ ------- -------
,CLARK,KING,MILLER, 8 12 4 KING
,ADAMS,FORD,JONES,SCOTT,SMITH, 8 12 4 FORD
注:instr(sourceString,destString,start,appearPosition).
其中sourceString代表源字符串;
destString代表想从源字符串中查找的子串;
start代表查找的开始位置,该参数可选的,默认为1;
appearPosition代表想从源字符中查找出第几次出现的destString,该参数也是可选的,默认为1;
而用正则表达函数regexp_substr就要简单的多:
select regexp_substr(v.name,'[^,]+',1,2) as 子串 from v;
子串
-------
KING
FORD
参数2:“^”在方括号里表示否的意思,+表示匹配1次以上,'[^,]+'表示匹配不包含逗号的多个字符,也就是本节view中的各个子串。
参数3:1表示从第一个字符开始。
参数4:2表示第二个能匹配'[^,]+'的字符串,也就是KING与FORD。
10.分析IP地址
本例要求把IP地址“192.168.1.118”中的各段取出来,用9节学到的方法,参数4分别取1,2,3,4即可:
select regexp_substr(v.ip, '[^.]+', 1, 1) a, regexp_substr(v.ip, '[^.]+', 1, 2) b, regexp_substr(v.ip, '[^.]+', 1, 3) c, regexp_substr(v.ip, '[^.]+', 1, 4) d from (select '192.168.1.118' as ip from dual) v;
A B C D
------ ------ -- ------
192 168 1 118
这是分拆字符常用的语句。
11.将分隔数据转换为多值IN列表
假设前端传入了一个字符串列表(如:张三,李四,李磊磊),要根据这个串查询数据:
select * from emp where ename in (...);
直接把张三,李四,李磊磊带入肯定是查不到数据的:
SQL> select * from emp where ename in ('张三,李四,李磊磊');
未选定行
我们需要做转换,这正是正则表达式的优势。
为了便于调用,我们先建立一个视图:
create or replace view v as select '张三,李四,李磊磊' as emps from dual;
结合前面所讲的知识,正则表达式如下:
select regexp_substr(v.emps,'[^,]+',1,level) as name,level from v connect by level <br> NAME LEVEL<br> --------- --------<br> 张三 1<br> <br> 李四 2<br> <br> 李磊磊 3<br> <br> <br> 那么结合本句就可以达到本例的需求。<br> <pre code_snippet_id="1692086" snippet_file_name="blog_20160522_37_6684991" name="code" class="sql">SQL> var v_emps varchar2(100); SQL> exec :v_emps := '张三,李四,李磊磊';
PL/SQL 过程已成功完成。
SQL> select * from emp where ename in ( select regexp_substr(:v_emps,'[^,]+',1,level) as ename from dual connect by level <br> EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO<br> ---------- -------------------- ------------------ ---------- -------------- ---------- ---------- ----------<br> 1110 张三 主管 3322 12-3月 -14 5200 20<br> <br> 1111 李四 销售 3321 03-11月-15 3400 500 30<br> <br> 1114 李磊磊 会计 3319 22-12月-15 2500 50<br> <br> 注:exec 是 execute 的缩写,功能是执行一个存储过程,或者是执行一个动态SQL。<br> <span style="color:#FF0000"><strong><br> 转载请注明出处:http://blog.csdn.net/acmman/article/details/51473622</strong></span><br>

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

HQL和SQL在Hibernate框架中進行比較:HQL(1.物件導向語法,2.資料庫無關的查詢,3.類型安全),而SQL直接操作資料庫(1.與資料庫無關的標準,2.可執行複雜查詢和資料操作)。

網易郵箱,作為中國網友廣泛使用的一種電子郵箱,一直以來以其穩定、高效的服務贏得了用戶的信賴。而網易信箱大師,則是專為手機使用者打造的信箱軟體,它大大簡化了郵件的收發流程,讓我們的郵件處理變得更加便利。那麼網易信箱大師該如何使用,具體又有哪些功能呢,下文中本站小編將為大家帶來詳細的內容介紹,希望能幫助到大家!首先,您可以在手機應用程式商店搜尋並下載網易信箱大師應用程式。在應用寶或百度手機助手中搜尋“網易郵箱大師”,然後按照提示進行安裝即可。下載安裝完成後,我們打開網易郵箱帳號並進行登錄,登入介面如下圖所示

12306訂票app下載最新版是一款大家非常滿意的出行購票軟體,想去哪裡就去那裡非常方便,軟體內提供的票源非常多,只需要通過實名認證就能在線購票,所有用戶的出行車票機票都可以輕鬆買到,享受不同的優惠折扣。還能提前開啟預約搶票,預約飯店、專車接送都是可以的,有了它想去哪裡就去那裡一鍵購票,出行更加簡單方便,讓大家的出行體驗更舒服,現在小編在線詳細為12306用戶帶來查看歷史購票記錄的方法。 1.打開鐵路12306,點擊右下角我的,點擊我的訂單 2.在訂單頁面點擊已支付。 3.在已支付頁

在如今雲端儲存已成為我們日常生活和工作中不可或缺的一部分。百度網盤作為國內領先的雲端儲存服務之一,憑藉其強大的儲存功能、高效的傳輸速度以及便捷的操作體驗,贏得了廣大用戶的青睞。而且無論你是想要備份重要文件、分享資料,還是在線上觀看影片、聽取音樂,百度網盤都能滿足你的需求。但很多用戶可能對百度網盤app的具體使用方法還不了解,那麼這篇教學就將為大家詳細介紹百度網盤app如何使用,還有疑惑的用戶們就快來跟著本文詳細了解一下吧!百度雲網盤怎麼用:一、安裝首先,下載並安裝百度雲軟體時,請選擇自訂安裝選

MetaMask(中文也叫小狐狸錢包)是一款免費的、廣受好評的加密錢包軟體。目前,BTCC已支援綁定MetaMask錢包,綁定後可使用MetaMask錢包進行快速登錄,儲值、買幣等,且首次綁定還可獲得20USDT體驗金。在BTCCMetaMask錢包教學中,我們將詳細介紹如何註冊和使用MetaMask,以及如何在BTCC綁定並使用小狐狸錢包。 MetaMask錢包是什麼? MetaMask小狐狸錢包擁有超過3,000萬用戶,是當今最受歡迎的加密貨幣錢包之一。它可免費使用,可作為擴充功能安裝在網絡

學信網如何查詢自己的學歷?在學信網中是可以查詢到自己的學歷,很多用戶都不知道如何在學信網中查詢到自己的學歷,接下來就是小編為用戶帶來的學信網查詢自己學歷方法圖文教程,感興趣的用戶快來一起看看吧!學信網使用教程學信網如何查詢自己的學歷一、學信網入口:https://www.chsi.com.cn/二、網站查詢:第一步:點選上方學信網位址,進入首頁點選【學歷查詢】;第二步:在最新的網頁中點選如下圖箭頭所示的【查詢】;第三步:之後在新頁面點選【的登陸學信檔案】;第四步:在登陸頁面輸入資料點選【登陸】;

小米汽車軟體提供遠端車控功能,讓使用者可以透過手機或電腦遠端控制車輛,例如開關車輛的門窗、啟動引擎、控制車輛的空調和音響等,下文就是這個軟體的使用及內容,一起了解下吧。小米汽車app功能及使用方法大全1、小米汽車app在3月25日上線蘋果AppStore,現在安卓手機的應用商店中也可以下載了;購車:了解小米汽車核心亮點和技術參數,可預約試駕、配置訂購您的小米汽車,支援線上處理提車待辦事項。 3.社群:了解小米汽車品牌資訊,交流用車體驗,分享精彩車生活;4、車控:手機就是遙控器,遠端控制,即時安防,輕

1.先開啟pycharm,進入到pycharm首頁。 2.然後新建python腳本,右鍵--點選new--點選pythonfile。 3.輸入一段字串,代碼:s="-"。 4.接著需要把字串裡面的符號重複20次,代碼:s1=s*20。5、輸入列印輸出代碼,代碼:print(s1)。 6.最後運行腳本,在最底部會看到我們的回傳值:-就重複了20次。
