2011-05-10 109 views
0

我目前正在爲我們的網站構建基於SQL Server全文索引的搜索功能,並且需要將用戶的輸入分成一組搜索條件。一旦條款被拆分,我需要將它們重新構建成一個包含將針對CONTAINS()或CONTAINSTABLE()全文查詢執行的查詢的字符串。SQL Server字符串操作 - 拆分搜索條件並構建新字符串

例如,如果用戶輸入

Jon Sidnell 

到我們的搜索框,我希望能夠以該字符串轉換成如下:

'("jon*" OR FORMSOF(THESAURUS, jon) OR FORMSOF(INFLECTIONAL, jon)) OR 
("sidnell*" OR FORMSOF(THESAURUS, sidnell) OR FORMSOF(INFLECTIONAL, sidnell))' 

顯然,如果有三個詞在用戶輸入中,將有三組「通配符或同義詞庫或折點」術語。作爲一個T-SQL新手(不是新手,但肯定不是大師!)我不確定最好的方式去解決這個問題。我已經搜索了一下,雖然我遇到了有助於初始字符串分割的事情,但我並沒有真正瞭解如何最好地使用該分割表示來構造結果字符串。

任何人都可以幫忙嗎?

回答

1

我不知道這是否是最有效的方法來解決您的問題,但想到的一點是封裝邏輯將輸入字符串拆分爲表值函數。

調用函數並將結果存儲到表變量中。

對錶變量進行迭代並將拆分字符串連接成用於搜索的最終字符串。

我還沒有列入該函數的代碼在這裏(爲簡潔起見),但對我來說我的函數接受分割字符串分隔符拆分的字符串並返回一個表具有以下結構:Position INT, Value VARCHAR(8000)

一旦你擁有了功能的地方,你可以將它類似於以下:

SET NOCOUNT ON 

DECLARE @sampleString VARCHAR(500) 
SET @sampleString = 'Jon Sidnell Rocks' 

DECLARE @delimiter VARCHAR(20); 
SET @delimiter = ' ' 

DECLARE @SplitResults TABLE (
    POSITION INT, 
    VALUE VARCHAR(8000), 
    fUsed BIT DEFAULT 0) 

INSERT INTO @SplitResults (POSITION, VALUE) 
SELECT * FROM dbo.ufn_SplitString(@sampleString, @delimiter) 

--Set up a simple loop instead of having to open up a cursor 
DECLARE @Value VARCHAR(8000); 
DECLARE @Position INT; 
SELECT @Value = q.VALUE, @Position = q.Position 
FROM (SELECT TOP 1 VALUE, Position FROM @SplitResults WHERE fUsed = 0)q 

DECLARE @SearchString VARCHAR(8000) 
WHILE @@ROWCOUNT <> 0 AND @Value IS NOT NULL 
BEGIN 

    IF @Position = 1 
    BEGIN 
     SET @SearchString = '("' + @Value + '*" OR FORMSOF(THESAURUS, '+ @Value +') OR FORMSOF(INFLECTIONAL, ' + @Value + '))' 
    END 
    ELSE 
    BEGIN 
     SET @SearchString = @SearchString + ' OR ("' + @Value + '*" OR FORMSOF(THESAURUS, '+ @Value +') OR FORMSOF(INFLECTIONAL, ' + @Value + '))' 
    END 

    --Update record so we know we used it 
    UPDATE @SplitResults SET fUsed = 1 
    WHERE Position = @Position AND VALUE = @Value 

    --Get Next Value to Work With 
    SELECT @Value = q.VALUE, @Position = q.Position 
    FROM (SELECT TOP 1 VALUE, Position FROM @SplitResults WHERE fUsed = 0)q 
END 

PRINT @SearchString; 

SET NOCOUNT OFF; 

輸出應該是這個樣子:

("Jon*" OR FORMSOF(THESAURUS, Jon) OR FORMSOF(INFLECTIONAL, Jon)) OR ("Sidnell*" OR FORMSOF(THESAURUS, Sidnell) OR FORMSOF(INFLECTIONAL, Sidnell)) OR ("Rocks*" OR FORMSOF(THESAURUS, Rocks) OR FORMSOF(INFLECTIONAL, Rocks)) 
1

如果您使用SQLCLR用戶定義的函數來分割字符串,則會有相當不錯的字符串操作方法。您可以使用以下字符串併爲每個搜索詞應用String.Format方法。它應該足夠快,除非有極高的音量,甚至可能。

「(\」{0} * \ 「OR FORMSOF(詞庫,{0})OR FORMSOF(INFLECTIONAL,{0}))」

public static SqlString convertStringToFTS(SqlString input) 
{ 
    string[] strings = input.ToString().Split(new string[] {" "}, StringSplitOptions.RemoveEmptyEntries); 

    StringBuilder sb = new StringBuilder(); 
    foreach (string s in strings) 
    { 
     if (sb.Length > 0) 
     { 
      sb.Append(" OR "); 
     } 
     else 
     { 
      sb.Append ("("); 
     } 
     sb.Append(string.Format("(\"{0}*\" OR FORMSOF(THESAURUS, {0}) OR FORMSOF(INFLECTIONAL, {0}))", s)); 
    } 
    sb.Append(")"); 
    return sb.ToString(); 
} 

我會說,有可能是更有效意味着實現這一點。

祝你好運。我希望這有幫助。

+0

啊,我忘記了SQL Server中的CLR代碼。這實際上似乎是一個非常好的選擇,雖然性能有點不明。將不得不看更接近... – jonsidnell 2011-05-11 09:16:17