三年不看一次書,一次看書看三年,三天不寫一次代碼,寫一次代碼寫三天.數據庫
呵呵,開個玩笑,話說今天在一本書(SQL Cookbook )上看到了一個怪異的要求:函數
表中的數據混亂了(真奇葩),皆爲如下這種前面是字符,後半是數字的狀況.測試
FHDJKHJ30003d
JKGLF434354blog
FHYDJ67889索引
要求是在查詢的時候僅查每一個值中的數字(或者說是字母,思路同樣).字符串
FHDJKHJ3000 --只要結尾的 3000 ,而不要前面的 FHDJKHJ get
當我正感興趣的時候,書中介紹的在幾個數據庫管理軟件中實現的方式:string
DB2 / Oracle / PostgreSQL 等裏面用 TRANSLATE 函數 REPLACE 函數進行操做.it
可是書中沒有 SQL SERVER 中的實現方案,這讓我很鬱悶,難道我熟知的 SQL SERVER 不具有此功能?
我嘗試了書中的方法,但 SQL SERVER 中貌似沒有這兩個函數(時勢造博文,不然就不會有這篇口水文了...).
至少個人2008聯機叢書和SERVER 2012 中查不到那兩個函數,哪位大牛要知道相似的SQL SERVER 函數,還請告訴我.
因而,我就萌發了一個想法,能不能本身定義一個函數,實現從字符串中分離出結尾的數字呢?
因而我想弄個函數,函數中作的事情就是從傳入的字符串中一次次的截取出來嘗試轉換爲數字,成功則返回.
假設傳入的是 'AB38' 則獲得數字 38 ,它的原理爲一次次截取並嘗試轉換,如 'AB38' 的匹配過程:
第一次截取 'AB38' 轉換,結果確定失敗.
第二次截取 'B38' 轉換失敗.
第三次截取 '38' 轉換成功,返回 38
咱們的初衷是要得到傳入字符串後面的數字.
沒有圖你說 J* 啊! 呵呵 這就附上咱們的倫理圖....
咱們能夠看出咱們的步驟,無論字符串多長,咱們都是這個步驟進行,從前日後依次排除,直到成功.
最壞狀況咱們得測試到最後才成功,最糟糕的狀況是咱們測試到最後還沒成功...
因而我建立了函數:
-- 得到傳入字符串後面的數字,並返回
CREATE FUNCTION MyConvertAndGetNumber(@string nvarchar(MAX))
RETURNS INT -- 返回值是 int 類型.
BEGIN
-- 參數長度,下標索引,返回數字
DECLARE @length int= len(@string),@index int = 1,@number int
-- 動態長度,切後的字符串
DECLARE @newLength int=@LENGTH,@newString nvarchar(max)WHILE(@INDEX <= @length)
BEGIN
SELECT @newString =SUBSTRING(@string,@index,@newLength)
SELECT @number = TRY_CONVERT(int,@newString) –-咱們是嘗試轉換,不成功獲得 null
IF(@number >=0) -- @number 可能爲 null,但 null >= 0 永遠爲假,既必須轉換成功條件才爲真
BEGIN
RETURN @NUMBER
END
SELECT @newLength=@length-@index
SELECT @INDEX=@INDEX+1
END
RETURN @NUMBER
END
能夠看出咱們定義了一堆讓人眼花的變量,可是沒辦法,咱們必須這樣作.
因爲字符串長度未知,所以參數 @string 選擇了 nvarchar(max).
函數返回值是 int (至少咱們認爲捕獲成功後是這樣的).
因爲截取字符串的時候,最左端起碼從 1 開始截取,因此咱們 @index 初始化爲 1.
@newLength 表示的咱們循環截取字符串時每次要截取的長度.
@newString 表示的是咱們每次截得的字符串.
首先咱們 SELECT @newString =SUBSTRING(@string,@index,@newLength) 獲得截取字符串(第一次是所有).
而後是 SELECT @number = TRY_CONVERT(int,@newString) 嘗試轉換, try_convert() 不成功會返回 null.
所以咱們接着判斷是否成功,因爲 null 不會大於等於 0 ,只有爲數字的時候纔會爲 true 條件,條件一旦爲true 則成功,咱們就返回.
可是若是不成功,咱們就繼續進行日後切取字符串,固然這必須把截取長度 @newLength 和 起始下標位置 @index 對應遞增和遞減.
一直循環下去,直到成功或者失敗,而後返回結果,
咱們在使用的時候提示一點的是,咱們的函數可能返回 null(當全部嘗試失敗的時候),所以咱們要進行一個子查詢過濾:
select * from
(select dbo.MyConvertAndGetNumber(str) as number from TempTable) as t1
where number>0
感興趣的朋友能夠試試哦!頗有趣的哦.
個人老師說,世界這麼亂,要學東西就學不變的,什麼是不變的呢? 答案是: 真理,理論,思路...
在你掌握了這些不變的東西以後,儘管有的時候咱們沒有這東西,可是咱們能夠用現有的東西去實現咱們要實現的東西,從而 "拼湊" 或 "建造" 一個具備新功能的東西,那麼你的自學能力或者說是創新能力就很棒!
一樣,舉一反N:
如今你能建造用於提取字符串中穿插(如: fd78HJK8HJF9)的數字,而後拼接爲新的字符串了嗎?
如今你能建造用於提取字符串裏邊最後爲數字且有三位以上位數的數字了嗎?
如今你能建造用於提取字符串(fdjskl789)前面的字符的方法嗎?
.....
謝謝你看到這裏,如下是廢話,朋友,你能夠 ctrl+w 了!
事就這麼個事,不過我相信看到此處的你已經明白了!要感興趣但不大明白,能夠 home 一下繼續查看.
要知道,心有多狠,想法就有多狠,寫出的代碼天然就狠.
好的,朋友,再見!