Sql-Server

在找到一個子字元串時,也要找到結束位置

  • September 9, 2022

一個LIKE子句可以測試一個字元串是否出現在另一個字元串中,並且該CHARINDEX函式可以給出第一個匹配項的開始位置。

就我而言,我對結束位置感興趣,因為排序規則的複雜性,不能從開始位置推導出來。例如,在德語歸類 ( German_PhoneBook_100_CI_AS_SC_UTF8) 中,

  • 出現在位置 1 的“Häger”中並在位置 2 處結束,並且
  • 出現在位置 1 的 ‘Haeger’ 中,並在位置 3 結束。

這樣做的問題是為使用者的利益標記搜尋結果文本的匹配部分。

我一直在考慮反轉字元串,但是我仍然只能得到第一個匹配項,CHARINDEX在這種反轉的情況下,我需要最後一個匹配項。

有什麼想法嗎?

以下是我認為可行的新嘗試,但比此答案中發布的第一個嘗試要復雜得多。

基於使用的想法,但必須處理替換所有而不只是第一次出現replace的事實,我現在用包含可辨識分隔符的東西替換匹配項,我可以找到它來分隔其餘部分。然後我可以刪除其餘部分並查看剩餘部分的長度。replace``charindex

但是,讓我們做出以下假設以使我們的生活更輕鬆一些,即使有這些限制,它也會變得非常複雜:

  1. 假設搜尋字元串位於待搜尋源的開頭。這是我實際需要解決我的問題的情況,但也可能存在更通用的解決方案。
  2. 分隔符不在源中。在我自己的情況下,我可以選擇一個異國情調的字元並忍受這個功能不適用於它實際出現的那個罕見的字元串。(我當然先檢查。)
  3. 為了不必在查詢中指定排序規則,我假設查詢在具有排序規則 German_PhoneBook_100_CI_AS_SC_UTF8 的數據庫中執行 - 確保在執行時執行相同操作或添加排序規則說明符。

首先,這是一個程序化版本:

declare @sep char(1) = '|'
declare @source varchar(60) = 'haegerhae'
declare @tofind varchar(60) = 'hä'

declare @helper varchar(61) = concat(@tofind, @sep)

declare @temp varchar(60) = replace(@source, @tofind, @helper)
declare @l int = charindex(@sep, @temp, 1)

declare @unwanted varchar(60) = replace(substring(@temp, @l + 1, len(@temp) - @l), @sep, '')

select @temp temp, @unwanted unwanted, replace(@source, @unwanted, '') result;

其餘部分顯示為hae,它還通過長度告訴我們結束位置。

這是相同方法的單查詢版本:

with helper (v) as (
   select concat(@tofind, @sep) v
), temp (v) as (
   select replace(@source, @tofind, v) v from helper
), l (v) as (
   select charindex(@sep, v, 1) v from temp
), unwanted (v) as (
   select replace(substring(temp.v, l.v + 1, len(temp.v) - l.v), @sep, '') from temp cross join l
)
select replace(@source, v, '') from unwanted

CHARINDEX 將給出比賽的飛鏢。使用 STUFF 插入 @sep。這將打破比賽。一次前進一個位置,直到比賽恢復。這將結束源。

haeger   match at position 1   
h|aeger  no match    
ha|eger  no match    
hae|ger  match    

因此,比賽從位置 1 延伸到 3(含)。

如果原始字元串中有多個匹配項,這將在第一次填充 @sep 後顯示。在這種情況下,可以從那裡截斷原件並以這種方式進行搜尋。

抱歉,我目前無法清楚地輸入此內容。明天吧。希望它仍然有用。

引用自:https://dba.stackexchange.com/questions/316647