轉載自:https://www.2cto.com/database/201802/718583.html
7.6.1 生成自增值
需求:
通過SQL生成一個1到1000條記錄.
解決方法:
通過CTE的遞歸來實現該需求.
SQLServer:
?
1
2
3
4
5
6
7
8
9
10
11
DECLARE @startINT, @endINT
SELECT @start=1, @end=1000
;WITH NumberSequence( Number) AS
(
SELECT @start ASNumber
UNION ALL
SELECT Number + 1
FROM NumberSequence
WHERE Number <@end
)
SELECT * FROM NumberSequence OPTION(MaxRecursion 1000)
執行結構:
Number
1
2
3
4
5
6
7
8
9
10
…
Oracle:
?
1
2
3
4
5
6
7
WITH t(num)AS (
SELECT 1 FROM DUAL
UNION ALL
SELECT t.num+1
FROM t WHERE t.num<100
)
SELECT * FROM t;
執行結果:
Num
1
2
3
4
5
6
7
8
9
10
…
Mysql(8.0及以上版本):
?
1
2
3
4
5
6
7
WITH RECURSIVE cte (num) AS
(
SELECT 1
UNION ALL
SELECT num+1 FROM cte WHERE num <100
)
SELECT * FROM cte;
執行結果:
Num
1
2
3
4
5
6
7
8
9
10
…
7.6.2 遍歷字符串裏的每個值
需求:
打印出ename爲’King’的名字裏每一個字母,每個字母佔一行.
解決方法:
通過自增表和emp表先cross join(笛卡爾積),然後再通過ename的len(ename的長度)進行過濾,最終得到顯示每個字母的結果.
SQLServer:
?
1
2
3
4
SELECT SUBSTRING (e.ENAME,seq.pos,1) AS ename_Split
FROM (SELECT ENAME FROM emp WHERE ename= 'KING' ) e,
(SELECT number AS pos FROM master.[dbo].[spt_values] WHERE type = 'P' AND number>0)seq
WHERE seq.pos <= LEN(e.ename)
執行結果:
ename_Split
K
I
N
G
注:
1: 這裏master.[dbo].[spt_values]是一張特殊的系統視圖,裏面存了從0到2047總2048條自增序列.
2: 如果不明白,可以分段來看.
Step1:
?
1
2
3
SELECT e.*,seq.* FROM
(SELECT ENAME FROM emp WHERE ename= 'KING' ) e,
(SELECT number AS pos FROM master.[dbo].[spt_values] WHERE type = 'P' AND number>0)seq
執行結果:
ENAME
pos
KING
1
KING
2
KING
3
KING
4
KING
5
KING
6
KING
7
KING
8
…
…
Sept2:
?
1
2
3
SELECT SUBSTRING(e.ENAME,seq.pos,1)AS ename_Split
FROM .. e, ..seq
WHERE seq.pos<=LEN(e.ename)
這裏通過SUBSTRNG函數,每次的開始位置不斷調整,每次僅取一個字符,再通過LEN函數過濾.所以得到最終結果.如果不熟悉SUBSTRING的語法,這裏簡單介紹下.
SUBSTRING ( expression, start, length )
1) 參數expression是要截取的原始字符串,比如這裏的” KING”
2) 參數start是要截取的位置,比如從第2個位置開始,那應該從” I”往後數.
3) 參數length是要截取的長度,沿用上一行的例子,如果長度定義爲2,則最終截取字符串是”IN”
Oracle:
?
1
2
3
4
5
6
7
8
9
10
WITH t(num) AS (
SELECT 1 FROM DUAL
UNION ALL
SELECT t.num+1
FROM t WHEREt.num<100
)
SELECT SUBSTR(e.ENAME,seq.num,1) AS ename_Split FROM
(SELECT ENAME FROM emp WHERE ename ='KING' ) e,
(SELECT num FROM t)seq
WHERE seq.num <= LENGTH(e.ename)
Mysql8.0:
?
1
2
3
4
5
6
7
8
9
10
WITH RECURSIVE cte (num)AS
(
SELECT 1
UNION ALL
SELECT num+1 FROM cte WHERE num <100
)
SELECT SUBSTRING(e.ENAME,seq.num,1) AS ename_Split FROM
(SELECT ENAME FROM emp WHERE ename ='KING' ) e,
(SELECT num FROM cte)seq
WHERE seq.num <= LENGTH(e.ename)
7.6.3 處理含引號的字符串
需求:
往dept表裏插入dname爲Test’s,loc爲Beijing,deptno爲100的數據.
解決方法:
這裏有位引號是特殊符號,所以需要特殊處理,比如如果雙引號包裹起來.
Mysql:
?
1
INSERT INTO dept VALUES(100,'Test\'s','Beijing');
Sql Server:
?
1
2
3
4
5
6
7
8
BEGIN TRAN
SET IDENTITY_INSERTdeptON;
GO
INSERT INTO dept(deptno,dname,loc) VALUES (100,'Test''s','Beijing');
SELECT * FROM dept WHERE deptno=100;
SET IDENTITY_INSERTdeptOFF;
GO
ROLLBACK TRAN
執行結果:
deptno
dname
loc
100
Test's
Beijing
7.6.4 計算某個字符出現的次數
需求:
查詢emp表emptno是7499的用戶的job裏S出現的次數.
解決方法:
這裏length(len)結合replace函數算出字符串出現的次數.
Sql Server:
?
1
2
SELECT empno,job,(LEN(JOB) - LEN(REPLACE(JOB,'S','')))/LEN('S') AS StrFreq
FROM emp WHERE empno=7499;
empno
job
StrFreq
7499
SALESMAN
2
Mysql:
?
1
2
SELECT empno,job,ROUND((LENGTH(JOB) - LENGTH(REPLACE(JOB,'S','')))/LENGTH('S')) AS StrFreq
FROM emp WHERE empno=7499;
注:這裏除以LENGTH('S')是爲了考慮傳入的字符串是2位以及以上的情況,比如’SS’.
7.6.5 字符串裏過濾不需要的字符
需求:
過濾tmp_v視圖裏含數字的部分. 其中tmp_v視圖的data字段的定義是emp表的ename字段拼接空格和deptno字段。
解決方法:
這裏通過translate函數對含數字的部分進行替換.
SQL Server:
?
1
2
3
4
5
6
create view tmp_v
AS SELECT ename+' '+cast(deptno as varchar)as data
from emp
SELECT data,replace(dbo.translate(data,'0123456789','@@@@@@@@@@'),'@','') as ename FROM tmp_v
order by replace(dbo.translate(data,'0123456789','@@@@@@@@@@'),'@','') desc
data
ename
WARD 30
WARD
TURNER 30
TURNER
SMITH 20
SMITH
SCOTT 20
SCOTT
MILLER 10
MILLER
MARTIN 30
MARTIN
KING 10
KING
JONES 20
JONES
JAMES 30
JAMES
FORD 20
FORD
CLARK 10
CLARK
BLAKE 30
BLAKE
ALLEN 30
ALLEN
ADAMS 20
ADAMS
注:這裏需要參考之前章節裏translate函數的實現.
Mysql:
?
1
2
3
4
5
6
create view tmp_v
AS SELECT CONCAT(ename,' ',deptno) as data
from emp
SELECT data,replace(translate(data,'0123456789','@@@@@@@@@@'),'@','') as ename
FROM tmp_v
order by replace(translate(data,'0123456789','@@@@@@@@@@'),'@','') desc
Oracle:
7.6.6 拆分字符串裏的字符和數字
需求:
過濾tmp_v視圖裏data字段拆分會原來的ename和deptno兩個字段.
解決方法:
這裏通過translate、replace、repeate(replicate、rpad)函數對含數字的部分進行替換.
SQLServer:
?
1
2
3
4
SELECT data,replace(dbo.translate(data,'0123456789',REPLICATE('@',10)),'@','') as ename,
replace(dbo.translate(data,'ABCDEFGHIJKLMNOPQRSTUVWXYZ',REPLICATE('@',26)),'@','') as deptno
FROM tmp_v
order by replace(dbo.translate(data,'0123456789',REPLICATE('@',10)),'@','') desc
data
ename
deptno
WARD 30
WARD
30
TURNER 30
TURNER
30
SMITH 20
SMITH
20
SCOTT 20
SCOTT
20
MILLER 10
MILLER
10
MARTIN 30
MARTIN
30
KING 10
KING
10
JONES 20
JONES
20
JAMES 30
JAMES
30
FORD 20
FORD
20
CLARK 10
CLARK
10
BLAKE 30
BLAKE
30
ALLEN 30
ALLEN
30
ADAMS 20
ADAMS
20
Mysql:
?
1
2
3
4
SELECT data,replace(translate(data,'0123456789',REPEAT('@',10)),'@','') as ename,
replace(translate(data,'ABCDEFGHIJKLMNOPQRSTUVWXYZ',REPEAT('@',26)),'@','') as deptno
FROM tmp_v
order by replace(translate(data,'0123456789',REPEAT('@',10)),'@','') desc
結果同上
Oracle:
7.6.7 判斷字符串是字符串數字型
需求:
檢索temp_strdata表的字段data是字符串數字類型的記錄這裏如果都是字符串或者數字的也符合條件.
解決方法:
這裏通過translate、replace、repeate(replicate、rpad)函數對含數字的部分進行替換.
SqlServer:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TABLE temp_str(data VARCHAR(1000));
INSERT INTO temp_str VALUES('SMITH20');
INSERT INTO temp_str VALUES('JONES30');
INSERT INTO temp_str VALUES('Jim#40');
INSERT INTO temp_str VALUES('50$Tom');
INSERT INTO temp_str VALUES('60:Mike');
INSERT INTO temp_str VALUES('70Cruz');
INSERT INTO temp_str VALUES('Jack');
INSERT INTO temp_str VALUES('J8oh0n');
SELECT data --,dbo.translate(UPPER(data),'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',REPLICATE('a',36)) as trans
FROM temp_str
WHERE dbo.translate(UPPER(data),'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',REPLICATE('a',36))=REPLICATE('a',LEN(data))
-- 或者用如下方法,思路通過判斷截取的每個字符的ASCII值來判斷區間是否落在[48,57],[97,122],落在的爲0,反之爲1,然後再通過對該Flag進行sum來判斷,如果等於0則說明數字字符型的.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT data -- ,SUM(Flag)
FROM
(
SELECT LOWER(data) as data,SUBSTRING(e.data,seq.pos,1)AS ename_Split,ascii(SUBSTRING(LOWER(e.data),seq.pos,1)) AS asci,
CASE WHEN ascii(SUBSTRING(LOWER(e.data),seq.pos,1))>= 48 AND ascii(SUBSTRING(LOWER(e.data),seq.pos,1))<=57 THEN 0
WHEN ascii(SUBSTRING(LOWER(e.data),seq.pos,1))>= 97 AND ascii(SUBSTRING(LOWER(e.data),seq.pos,1))<=122 THEN 0 ELSE 1 END AS Flag
FROM temp_str e,
(SELECT number AS pos FROM master.[dbo].[spt_values]WHERE type = 'P' AND number>0) seq
WHERE seq.pos<= LEN(e.data)
-- ORDER BY data
)A
GROUP BY data
HAVING SUM(Flag) = 0
Mysql:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
SELECT data--,translate(UPPER(data),'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',REPEAT('a',36)) AS trans
FROM temp_str
WHERE translate(UPPER(data),'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',REPEAT('a',36))=REPEAT('a',LENGTH(data))
-- 利用正則表達式來匹配
SELECT data
FROM temp_str
WHERE data regexp'[^0-9A-Za-z]'=0
-- 待驗證Mysql8
WITH RECURSIVE cte (num) AS
(
SELECT 1
UNION ALL
SELECT num+1 FROM cte WHERE num <100
)
SELECT data-- ,SUM(Flag)
FROM
(
SELECT LOWER(data)as data,SUBSTRING(e.data,seq.pos,1) AS ename_Split,ascii(SUBSTRING(LOWER(e.data),seq.pos,1)) AS asci,
CASE WHEN ascii(SUBSTRING(LOWER(e.data),seq.pos,1))>=48 AND ascii(SUBSTRING(LOWER(e.data),seq.pos,1))<=57 THEN 0
WHEN ascii(SUBSTRING(LOWER(e.data),seq.pos,1))>=97 AND ascii(SUBSTRING(LOWER(e.data),seq.pos,1))<=122 THEN 0 ELSE 1 END AS Flag
FROM temp_str e,
(SELECT num FROM cte) seq
WHERE seq.pos<=LEN(e.data)
-- ORDER BY data
)A
GROUP BY data
HAVING SUM(Flag)=0
Oracle:
7.6.8 判斷字符串含有漢字
需求:
檢索含有漢字的字符串.
解決方法:
這裏通過函數CHAR_LENGTH對比LENGTH進行對比來判斷.
Mysql:
?
1
2
3
4
5
6
7
8
9
10
11
SELECT data,LENGTH(data) AS Len_data,CHAR_LENGTH(data) AS CharLen_Data,HEX(data) AS HexData FROM
(
SELECT 'Hello,World,SQL'AS data
UNION ALL
SELECT 'Data,Arithmetic' AS data
UNION ALL
SELECT 'Science中國' AS data
UNION ALL
SELECT '上S海H' AS data
)A
WHERE LENGTH(data) <> CHAR_LENGTH(data)
執行結果:
data
Len_data
CharLen_Data
Science中國
13
9
上S海H
8
4
注:
LENGTH() returnsthe length of the string measured in bytes.
CHAR_LENGTH() returns the length of the string measured incharacters.
LENGTH:是計算字節的長度.一個漢字是算三個字符,一個數字或字母算一個字符
CHAR_LENGTH:漢字、數字、字母都算是一個字符
或者通過字符串的十六進制並結合REGEXP來判斷.
?
1
2
3
4
5
6
7
8
9
10
11
SELECT data,HEX(data) AS HexData FROM
(
SELECT 'Hello,World,SQL' AS data
UNION ALL
SELECT 'Data,Arithmetic'AS data
UNION ALL
SELECT 'Science中國' AS data
UNION ALL
SELECT '上S海H' AS data
)A
WHERE HEX(data) REGEXP'^(..)*(E[4-9])'
執行結果:
data
HexData
Science中國
536369656E6365E4B8ADE59BBD
上S海H
E4B88A53E6B5B748
SQL Server:
SELECT data FROM
(
SELECT 'Hello,World,SQL'ASdata
UNION ALL
SELECT 'Data,Arithmetic'ASdata
UNION ALL
SELECT 'Science中國'ASdata
UNION ALL
SELECT '上S海H'AS data
)A
WHERE data LIKE '%[吖-座]%'
或者利用PATINDEX函數進行判斷
SELECTdata FROM
(
SELECT 'Hello,World,SQL'ASdata
UNION ALL
SELECT 'Data,Arithmetic'ASdata
UNION ALL
SELECT 'Science中國'ASdata
UNION ALL
SELECT '上S海H'AS data
)A
WHERE PATINDEX('%[吖-座]%',data)>0
執行結果:
data
Science中國
上S海H
Oracle:
7.6.9 合併多行到一行
需求:
將emp表裏deptno相同的ename以逗號拼接在一起.
解決方法:
這裏通過字符串合併函數完成該效果.如group_concat
SQL Server:
SELECT DISTINCT
deptno
, STUFF((
SELECT N', '+ CAST([ename]ASVARCHAR(255))
FROM emp e1
WHERE e1.deptno= e2.deptno
FOR XML PATH ('')), 1, 2,'')AS StrCombine
FROM emp e2
執行結果:
Deptno
StrCombine
10
CLARK, KING, MILLER
20
SMITH, JONES, SCOTT, ADAMS, FORD
30
ALLEN, WARD, MARTIN, BLAKE, TURNER, JAMES
或者藉助CTE:
WITH x(deptno,cnt,list,empno,len)
AS(
SELECT deptno,COUNT(*)OVER(PARTITIONBY deptno),CAST(enameASVARCHAR(100)),empno,1
FROM emp
UNION ALL
SELECT x.deptno,x.cnt,CAST(x.list+','+e.enameASVARCHAR(100)),e.empno,x.len+1
FROM emp e,x
WHERE e.deptno= x.deptno
AND e.empno> x.empno
)
SELECT deptno,listAS StrCombinefrom X
WHERE len=cnt
ORDER BY 1
步驟分析:
Step1: 首先借助COUNT(*) OVER(PARTITION BY deptno)確定每個部門裏有多少員工
Step2: 藉助len,初始值爲1,完成自增(遞歸裏 x.len+1)
Step3: 藉助x.list+','+e.ename完成ename的拼接
Step4: 藉助e.deptno = x.deptno AND e.empno >x.empno確定要遞歸的結果集
Step5: 查詢滿足條件的記錄,即按deptno分組的empno數和自增序號相同的記錄.
分步查看結果:
1) 查看構建的遞歸數據.這裏以depto=10的爲例:
SELECT *FROm xWHERE deptno= 10
deptno
cnt
list
empno
len
10
3
CLARK
7782
1
10
3
KING
7839
1
10
3
MILLER
7934
1
10
3
KING,MILLER
7934
2
10
3
CLARK,KING
7839
2
10
3
CLARK,MILLER
7934
2
10
3
CLARK,KING,MILLER
7934
3
2) 不難發現,這裏高亮處的數據是我們想要的,所以通過如下方式獲取最終結果:
SELECT deptno,listAS StrCombinefrom X
WHERE len=cnt
ORDER BY 1
延展閱讀:如果僅想獲得某一個分組下的字符串合併,也可以按照如下方法:
DECLARE@combinedString VARCHAR(MAX)
SELECT@combinedString = COALESCE(@combinedString+', ','')+ ename
FROM emp
WHERE deptno=10
SELECT@combinedString as StringValue
Mysql:
SELECT deptno,group_concat(ename)AS StrCombine FROm emp
GROUPBY deptno
ORDERBY emp.deptno,ename
7.6.10 對字符串重新按字母排序重新組合
需求:
將emp表裏ename按照字母順序重新組合生成新的字符.
解決方法:
這裏通過字符串合併函數或者結合substring和row_number完成該效果.
SqlServer:
WITH x(ename,ename_Split)AS
(
SELECT TOP 100000 ename,SUBSTRING(e.ENAME,seq.pos,1)AS ename_Split
FROM (SELECT ENAMEFROM emp) e,
(SELECT numberAS posFROMmaster.[dbo].[spt_values]WHEREtype = 'P' AND number>0) seq
WHERE seq.pos<=LEN(e.ename)
ORDER BY ename, ename_Split
)
SELECT DISTINCT
ename
, STUFF((
SELECT N''+ CAST(ename_SplitASVARCHAR(255))
FROM x e1
WHERE e1.ename= e2.ename
FOR XML PATH ('')),1,0,'')AS StrByAlph
FROM x e2
注: 如果想在CTE裏使用[]排序,需要在查詢裏指定TOP.
消息 1033,級別 15,狀態 1,第 67 行
除非另外還指定了 TOP、OFFSET 或 FORXML,否則,ORDER BY 子句在視圖、內聯函數、派生表、子查詢和公用表表達式中無效。
查詢結果:
ename
StrByAlph
ADAMS
AADMS
ALLEN
AELLN
BLAKE
ABEKL
CLARK
ACKLR
FORD
DFOR
JAMES
AEJMS
JONES
EJNOS
KING
GIKN
MARTIN
AIMNRT
MILLER
EILLMR
SCOTT
COSTT
SMITH
HIMST
TURNER
ENRRTU
WARD
ADRW
Mysql:
SELECT ename,group_concat(SUBSTRING(e.ENAME,seq.num,1)ORDERBYSUBSTRING(e.ENAME,seq.num,1)separator'')AS StrByAlph
FROM (SELECT ENAMEFROM emp) e,
(SELECT iAS numFROM tb_incr)seq
WHERE seq.num<=LENGTH(e.ename)
GROUPBY ename
ORDERBY ename,SUBSTRING(e.ENAME,seq.num,1)
注: 這裏藉助group_concat函數裏的ORDER BY關鍵字,對已經排序的字母進行合併.
Oracle:
7.6.11 判斷一個字符是否是數字
需求:
將臨時表裏判斷data字段裏哪些是數字.
解決方法:
這裏通過函數isnumberic或者regexp完成該效果.
Mysql:
DELIMITER $$
DROP FUNCTIONIFEXISTS `IsNum` $$
CREATE FUNCTION `IsNum`(strVARCHAR(25)) RETURNSINT
BEGIN
DECLARE iResultINTDEFAULT0;
IFISNULL(str)THENreturn0;END IF;-- NULL 字符串
IF str=''THENreturn0;END IF;-- 空字符串
SELECT strREGEXP'^[0-9]*$'INTO iResult;
IF iResult=1THEN
RETURN1;
ELSE
RETURN0;
END IF;
END $$
DELIMITER ;
或者使用正則表達式:
SELECT dataFROM
(
SELECT'63'AS data
UNIONALL
SELECT'36('AS data
UNIONALL
SELECT'3(6'AS data
UNIONALL
SELECT'(36'AS data
UNIONALL
SELECT'36$'AS data
UNIONALL
SELECT''AS data
UNIONALL
SELECTNULLAS data
)A
-- WHERE IsNum(data) = 1
WHERE data REGEXP'^[0-9]*$'=1AND data ISNOTNULLAND data<>'';
或者直接通過函數IsNum(data) = 1來判斷,見註釋部分.
SqlServer:
SELECT data FROM
(
SELECT '63'ASdata
UNION ALL
SELECT '36('ASdata
UNION ALL
SELECT '3(6'ASdata
UNION ALL
SELECT '(36'ASdata
UNION ALL
SELECT '36$'ASdata
UNION ALL
SELECT ''AS data
UNION ALL
SELECT NULLASdata
)A
WHERE ISNUMERIC(data)= 1
執行結果:
Data
63
7.6.12 按照指定的位置截取字符
需求:
按照逗號拆分字符串,取拆分出來的第二個子串.
解決方法:
這裏需要自定義函數結合substring截取字符串,以達到該效果.
SQL Server:
CREATE FUNCTION strSplitIndex
( @str VARCHAR(1024), --要分割的字符串
@split VARCHAR(10), --分隔符
@index INT --要取元素的位置
)
RETURNS VARCHAR(1024)
AS
BEGIN
DECLARE @location INT
DECLARE @start INT
DECLARE @next INT
DECLARE @seed INT
SET @str=LTRIM(RTRIM(@str))
SET @start=1
SET @next=1
SET @seed=LEN(@split)
SET @location=CHARINDEX(@split,@str)
WHILE @location<>0and @index>@next
BEGIN
SET @start=@location+@seed
SET @location=CHARINDEX(@split,@str,@start)
SET @next=@next+1
END
IF @location =0 SELECT @location =LEN(@str)+1
RETURN SUBSTRING(@str,@start,@location-@start)
END
GO
SELECT dbo.strSplitIndex(data,',',1)AS StrSplit FROM
(
SELECT 'Hello,World,SQL'AS data
UNION ALL
SELECT 'Data,Arithmetic'AS data
UNION ALL
SELECT 'Science' AS data
)A
執行結果:
StrSplit
Hello
Data
Science
或者藉助parsename函數:
SELECT PARSENAME(REPLACE(data,',','.'),2)AS StrSplit FROM
(
SELECT 'Hello,World,SQL'ASdata
UNION ALL
SELECT 'Data,Arithmetic'AS data
UNION ALL
SELECT 'Science' AS data
)A
WHERE PARSENAME(REPLACE(data,',','.'),2)ISNOT NULL
執行結果:
StrSplit
Hello
Data
Mysql:
SELECT data,SUBSTRING_INDEX(SUBSTRING_INDEX(data,',',seq.num),',',-1)AS sub,seq.num AS subStrPos
FROM
(SELECT'Hello,World,SQL'AS data
UNIONALL
SELECT'Data,Arithmetic'AS data
UNIONALL
SELECT'Science'AS data) e,
(SELECT ias numFROM tb_incr)seq
WHERE seq.num<=LENGTH(e.data)-LENGTH(REPLACE(e.data,',',''))+1
AND seq.num=2
ORDERBY data,seq.num
執行結果:
data
sub
subStrPos
Data,Arithmetic
Arithmetic
2
Hello,World,SQL
World
2
步驟解析:
Step1: 首先借助自增表將data字段裏的數據按照逗號的數目切分,如果有2個逗號,則會切分成3部分
Step2: 藉助SUBSTRING_INDEX函數截取逗號所在位置的子串,這裏鑑於SUBSTRING_INDEX的第三個參數的意義是子串累加,所以又套了個SUBSTRING_INDEX,第三個參數傳-1,即從右邊截取.
Step3:藉助自增表的num,取指定分割位置的數據,這裏是2.
注: SUBSTRING_INDEX函數執行示例見下:
SELECTSUBSTRING_INDEX('Hello,World,SQL',',',1)ASSUBSTRING,1AS pos
UNIONALL
SELECTSUBSTRING_INDEX('Hello,World,SQL',',',2)ASSUBSTRING,2AS pos
UNIONALL
SELECTSUBSTRING_INDEX('Hello,World,SQL',',',3)ASSUBSTRING,3AS pos
執行結果:
SUBSTRING
pos
Hello
1
Hello,World
2
Hello,World,SQL
3
Oracle:
7.6.13 按照指定的分隔符截取字符返回表形式
需求:
按照逗號拆分字符串,並指定返回的格式是表.
解決方法:
這裏需要自定義函數結合substring截取字符串,以達到該效果.
SQLServer:
CREATE FUNCTION strSplitTable(@strNVARCHAR(2000),@splitNVARCHAR(2))
RETURNS @t TABLE(SubStr VARCHAR(1000))
AS
BEGIN
DECLARE@tmpSubStr VARCHAR(1000),@getIndexINT
SET @getIndex=CHARINDEX(',',@str)
WHILE(@getIndex<>0)
BEGIN
SET @tmpSubStr=CONVERT(VARCHAR(1000),SUBSTRING(@str,1,@getIndex-1))
INSERT INTO @t(SubStr)VALUES(@tmpSubStr)
SET @str=STUFF(@str,1,@getIndex,'')
SET @getIndex=CHARINDEX(',',@str)
END
INSERT INTO @t(SubStr)VALUES(@str)
RETURN
END
GO
SELECT *FROm strSplitTable('Hello,World,SQL',',')
執行結果:
SubStr
Hello
World
SQL