前言:
本次要來說說如何用SQL來查詢特定字元出現的次數。
為何會有這種需求呢(特別是製造業常用的ERP)? 主因是很多時候ERP的功能無法與時俱進或是因為成本考量,而缺少部分功能,但又需要記錄一些資料作為篩選之類的用途,因此會把一些篩選條件等文字存入用於存放敘述性的欄位當中。但倘若只是用於篩選,其實針對特定欄位撰寫 LIKE ‘%想要搜尋的字串%’也就把問題解決了。
那為何要數字串出現的數目?
以作者親身的經驗,是因為有些耗材的領用量難以估計,也不會列在BOM表,但那種類的耗材相當昂貴,所以該公司還是需要知道預估的耗用數量,而此耗材品名有記錄於規格當中,當規格撰寫越多次此耗材,代表我們可以預期會使用到的耗材數量越多。
所以接下來作者就會以自己的思路與大家討論可能的作法,以及網路上看到的不錯做法。
內文:
如何找出特定字串?
如果今天不考量字串被找到的次數,而我們只要找到或是知道字串出現在哪,其實在MSSQL(SQL
Server 2008以後的版本)裡面有兩個函數可以使用,一個是CHARINDEX,另一個是PATINDEX。以下參考MSDN上的Transact-SQL的語法:
CHARINDEX (
expressionToFind , expressionToSearch [ , start_location ] )
PATINDEX (
'%pattern%' , expression )
所以對於大多數讀者來說,上面兩行語法非常清楚,CHARINEX就是將要尋找的字元(Char)放到參數1,而要被找搜尋的字元到參數2,而參數3則是選擇性的可用可不用,不使用則會預設為0,從被搜尋的字元第一個位置開始搜尋,反之,就會從使用者指定的位置開始找尋,該函數的回傳值則是第一次出現的起始位置。而PATINDEX顧名思義,就是用來找尋特定模式出現的位置,因此我們可以使用萬用字元,來描述字元的模式,若有符合則會回傳第一次出現的起始位置。
這兩個函數在SQL Server我常拿來用於切字串取得所需要的資料,因為資料庫有時候還是有描述性的資料,需要去蕪存菁一下。
如何找出特定字串出現的次數?
若比較直覺的想法,是以迴圈進行處理,配合上述介紹的兩個函數,若回傳值不為0,則代表出現次數+1,並從該回傳Index位置+查詢字元的長度之後繼續查詢。但網路上其實有提供一個特別的方法,巧妙的運用replace來達成,replace同樣也能達到查詢指定字元,並將將該指定字元以指定的字元取代。筆者通常會用replace來取代NULL值,來讓資料維持一致性。他的語法在T-SQL的網站上如下式:
REPLACE (
string_expression , string_pattern , string_replacement )
網路上有Oracle版本的文章,因此本文修改成以MSSQL-Server2008為例形式,假設我們有一個字串123x456x123x456,而我們要找尋x出現的次數,則我們以replace將查詢到的x以空白取代,則字串會縮短,而此縮短的長度總和除以單一一個要查詢的字元長度,就會是他被查詢到的次數。
範例Code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
程式目的:查詢特定字元於某資料庫欄位(字元)出現次數。 | |
範例解釋:以123x456x123x456此字串為例,找尋字元x出現的次數,結果顯示會查詢到3次x | |
詳細解釋可參考http://shuohsuanli-bear.blogspot.tw/2018/01/sql.html | |
程式撰寫者:李碩軒 | |
日期:2018/01/24 | |
*/ | |
SELECT | |
T.STRING | |
,(LEN(T.STRING) - LEN(REPLACE(T.STRING,'x',''))) / LEN('x') AS TIMES | |
FROM ( | |
SELECT '123x456x123x456' STRING | |
) T; |
執行結果:
參考資料:
學到了一課,謝謝
回覆刪除可以請問為甚麼要除以LEN('x')嗎,因為本來長度就整數了,那再除以LEN('x')=1的意義是甚麼
回覆刪除對於這個範例來說只有字元x,他的長度恰好為1,所以LEN('x')看起來就沒有影響。但舉個例子,如果是字串123x456xx789,然後我只要找xx,那麼寫成那個此時LEN('xx')就有用了。
刪除因此,這個範例中的LEN()其主要用途就是算特定字串被取代成為空發生的次數。