iT邦幫忙

0

SQL擷取部分字串

  • 分享至 

  • xImage

老闆給了我一個問題
雖然我覺得可能做不到..
但還是PO上來問問(說不定iT幫有神人!!)

就是有個Table的欄位內容格式大概如下..
"AA123(string123)"

其中..除了AA是固定的以外
AA之後的數字長度可能為3..可能為4..可能為5..不一定
後面的"()"不一定有
也就是可能只有"AA123"
而.."()"內的字串內容也不一定..

問..
如何只取得123這段數字..
PS:這段數字長度也不一樣...

(我有先了解過SQL語法有instr、substr、length等語法
也大致了解..用法..可是..怎麼應用到這個問題..= =)

看更多先前的討論...收起先前的討論...
Albert iT邦高手 1 級 ‧ 2017-06-09 14:57:51 檢舉
這不就是我們的 單據 分類別 可設定 前置碼 + 依據 年 或 年月 或 年月日
Albert iT邦高手 1 級 ‧ 2017-06-09 15:00:06 檢舉
從第三碼起可能 1 ..9碼是"數字"
哪不就依據trim後長度寫 sql 轉換
Albert iT邦高手 1 級 ‧ 2017-06-09 15:04:44 檢舉
CASE LENGHT( TRIM(FieldA))
WHEN 3 THEN TO_NUMBER(SUBSTR( TRIM(FieldA),3,1),'9')
WHEN 4 THEN TO_NUMBER(SUBSTR( TRIM(FieldA),3,2),'99')
WHEN 5 THEN TO_NUMBER(SUBSTR( TRIM(FieldA),3,3),'999')
WHEN 6 THEN TO_NUMBER(SUBSTR( TRIM(FieldA),3,4),'9999')
.... (自己繼續).....

ELSE 0 END
前輩的解法
似乎只去除前面的兩個字元
並從第3個字元取後面的字串
我這樣解釋沒錯吧?!

只不過..
跟我要問的問題..似乎只能解決一半..
因為我欄位中的字串除了要去除前面兩個字元
還要去除後面不確定有沒有且沒固定格式與字數的字元
只要取得中間字串

例如:AA1234(ABCD4321) => 1234
例如:AA123(CCBASD999999) => 123
例如:AA12345 => 12345
例如:AA1234567<321CHANGE987> => 1234567
Albert iT邦高手 1 級 ‧ 2017-06-09 20:14:39 檢舉
用包紮兩層先用 REGEXP_INSTR 取出位置減字頭為 Len1
\D Matches a nondigit character.
再用這個位置去取代
WHEN 3 THEN TO_NUMBER(SUBSTR( TRIM(FieldA),3,1),'9')
變成
WHEN 3 THEN TO_NUMBER(SUBSTR( TRIM(FieldA),3,Len1),'9')
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
0
小魚
iT邦大師 1 級 ‧ 2017-06-09 11:59:12
最佳解答

你一定要用SQL處理嗎?
不能用後端處理?

看更多先前的回應...收起先前的回應...

我知道..如果丟後端PHP處理是挺容易的..
我也大概知道怎麼做...
但BOSS的專案.因流程關係..
他想要在SQL解決..= =

小魚 iT邦大師 1 級 ‧ 2017-06-09 12:04:33 檢舉

MySql還是MS-SQL ?
(啊..PHP應該是MySql,我笨了..)

小魚 iT邦大師 1 級 ‧ 2017-06-09 12:37:33 檢舉

就我的瞭解這可能要用存儲過程來做了,
那一塊我比較不熟,
不過很好奇"流程"關係,一定不能用後端?

當然可以後端~
但BOSS叫我研究看看先~0.0

您提到儲存過程是??

補充:我的問題主要在查詢..
也就是..
Select 欄位(這欄位要經過上述字串處理擷取部分我要的字串)
From Table
Where 條件

小魚 iT邦大師 1 級 ‧ 2017-06-09 19:55:35 檢舉

存儲過程有點像在SQL寫程式,
英文關鍵字是Stored Procedure,
不過存儲過程有可能讓SQL變慢,
這部分我還沒研究過,
你可以先在存儲過程寫好內容,
然後呼叫存儲過程幫你撈出結果出來。

小魚 iT邦大師 1 級 ‧ 2017-06-10 00:43:14 檢舉

結果被我試出來了
///
SELECT Name,
(CASE WHEN LOCATE('(', Name) > 0 THEN SUBSTR(Name, 3, LOCATE('(', Name) - 3) ELSE SUBSTR(Name, 3, CHAR_LENGTH(Name) - 2) END) AS Name2
FROM PEOPLE
///
測試資料
AA1234 => 1234
AA12345(1234) => 12345
AA33548(4231) => 33548
AA57945 => 57945

您的方法我也試成功了~^..^
其實做這個是為了要把以前就有的資料創個新TABLE做個過濾與整理
原本是人工~但資料過於龐大~
所以BOSS才叫我研究看看怎麼下SQL會快一些
不過...好像還是回到人工~
不是您的方法行不通~
而是很早之前的資料庫做得不好~
他那個欄位被設計成類似備忘錄一樣~
供給使用者自由輸入~
雖然使用者也很有規律地輸入他們規定的輸入方式
大概像這樣 => |代碼|編號|紀錄|
代碼很固定..就兩碼
編號則有4~7碼的英數組合
紀錄被輸入得更自由了..
我原本以為只有'()'、'<>'或是空
沒想到還有這種人這樣紀錄 => AA12345中文字 或是 AA1234標點符號 ...
所以..我跟老闆說...這可能需要人工智慧了...= =
就像..樓下海綿寶寶說的..問SIRI..= =

小魚 iT邦大師 1 級 ‧ 2017-06-12 12:49:07 檢舉

太複雜只能用後端處理了...

圓頭人 iT邦研究生 5 級 ‧ 2019-03-11 14:55:31 檢舉

如果有試出什麼答案,其實也可以寫在問題裡啊...
這樣大大們也可以更接近你想解決的問題...

0
西郎摳ken
iT邦新手 5 級 ‧ 2017-06-09 17:16:11

利用數值+字串會成為NULL的道理去選擇 是不是這樣??
左取7包右取5 其中左取3(加上右取2)不是NULL 就是有值,就取右5

而左取3加上右取2包左取1不是NULL 就是有值,就取右4 其他的就取3

CASE LEFT(RIGHT(LEFT(A,7),5),3)+RIGHT(RIGHT(LEFT(A,7),5),2) WHEN NULL THEN (CASE LEFT(RIGHT(LEFT(A,7),5),3)+LEFT(RIGHT(RIGHT(LEFT(A,7),5),2),1) WHEN NULL THEN LEFT(RIGHT(LEFT(A,7),5),3) ELSE LEFT(RIGHT(LEFT(A,7),5),4) END) ELSE RIGHT(LEFT(A,7),5) END

0
海綿寶寶
iT邦大神 1 級 ‧ 2017-06-09 17:33:02
CREATE TABLE tbltest
    (`PONO` varchar(50))
;
    
INSERT INTO tbltest
    (`PONO`)
VALUES
    ('AA123'),
    ('AA1234'),
    ('AA12345'),
    ('AA123()'),
    ('AA1234(AA789)'),
    ('AA12345(AA789)'),
    ('AA1234(ABCD4321)'),
    ('AA123(CCBASD999999)'),
    ('AA12345'),
    ('AA1234567<321CHANGE987>')
;
SELECT 
CASE instr(pono,'(') 
WHEN 0 THEN SUBSTR(pono, 3)
ELSE SUBSTR(pono, 3, INSTR(PONO,'(')-3)
END
FROM tbltest

什麼?
不確定有沒有且沒固定格式與字數的字元?
那大概得找Siri來解決了...

恩.....是個好方法...

0
froce
iT邦大師 1 級 ‧ 2017-06-11 00:10:31

https://stackoverflow.com/questions/986826/how-to-do-a-regular-expression-replace-in-mysql
https://github.com/mysqludf/lib_mysqludf_preg

其他資料庫有regexp replace,不過mysql好像沒有...
上面的不知道還有沒有用,我不用mysql。

2
鮪魚蛋吐司
iT邦新手 5 級 ‧ 2017-06-14 10:40:06

您好,我是SQL新手,以下SQL程式碼應該有符合您的需求
但因為是新手所以可能寫得太複雜..有需要改進的地方再麻煩各位提點一下喔!
(環境:MS SQL SEVER2000)

SET NOCOUNT ON
-- 宣告變數
DECLARE @test1 varchar(30) ,@idx int

SET @idx = 3

-- 建表給值
DECLARE @RESULT_TABLE TABLE (tst_char VarChar(50));
DECLARE @pratice_tmp TABLE (tst_char VarChar(50));
INSERT INTO @pratice_tmp VALUES ('AA54321~~spf25254joisjo)')
INSERT INTO @pratice_tmp VALUES ('AB1234ever1th1ng')
INSERT INTO @pratice_tmp VALUES ('AC21測試test321>!<')
INSERT INTO @pratice_tmp VALUES ('BA787321。句號試試看111')
INSERT INTO @pratice_tmp VALUES ('CA54AAW11#@$5254jsjo)')
INSERT INTO @pratice_tmp VALUES ('DD08081456`11~5sjo`.')

-- 定義指標
DECLARE CSR_CATCH_NAME CURSOR FOR SELECT tst_char FROM @pratice_tmp

-- 開啟指標
OPEN CSR_CATCH_NAME 

-- 開始擷取資料
FETCH NEXT FROM CSR_CATCH_NAME INTO @test1;

WHILE @@FETCH_STATUS = 0  
BEGIN --取到非中英的字元為止
	WHILE (SUBSTRING(@test1,@idx,1) like '[A-Z]') OR 
		  (SUBSTRING(@test1,@idx,1) like '[a-z]') OR 
		  (SUBSTRING(@test1,@idx,1) like '[0-9]')	
	BEGIN
		SET @idx = @idx + 1;
	END

	INSERT INTO @RESULT_TABLE VALUES (SUBSTRING(@test1,3,@idx-3))
	SET @idx = 3

	FETCH NEXT FROM CSR_CATCH_NAME INTO @test1;
END

SELECT tst_char AS '編號' FROM @RESULT_TABLE

SET NOCOUNT OFF

已經給出最佳解了...= =
如果你早點出現..我就可以給你了~
只能給like了~
/images/emoticon/emoticon12.gif

沒關係的! 有稍微幫上點忙就好
還是新手 有練習機會最重要 !哈哈

0
cho010012
iT邦新手 5 級 ‧ 2022-12-13 10:10:25

https://blog.51cto.com/qubernet/5160826
參考此方式先設sql function 再去用function取欄位其數字部分
剛好也碰上發問者的問題找到解答。但處理的速度會較慢...

我要發表回答

立即登入回答