【问题标题】:SQL Server string manipulation - splitting search terms and building a new stringSQL Server 字符串操作 - 拆分搜索词并构建新字符串
【发布时间】:2011-05-10 13:10:45
【问题描述】:

我目前正在为我们的站点构建基于 SQL Server 全文索引的搜索功能,并且需要将用户的输入拆分为一组搜索词。拆分术语后,我需要将它们重新构建成一个字符串,其中包含将针对 CONTAINS() 或 CONTAINSTABLE() 全文查询执行的查询。

例如,如果用户输入

Jon Sidnell

进入我们的搜索框,我希望能够将该字符串转换为以下内容:

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

显然,如果用户输入中包含三个单词,则会有三组“通配符 OR 词库 OR 屈折”术语。

作为 T-SQL 新手(不是新手,但肯定不是专家!)我不确定解决此问题的最佳方法。我搜索了一下,虽然我遇到了有助于初始字符串拆分的事情,但我真的不知道如何最好地使用拆分的表示来构造结果字符串。

有人可以帮忙吗?

【问题讨论】:

    标签: sql-server tsql string


    【解决方案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))
    

    【讨论】:

      【解决方案2】:

      如果您使用 SQLCLR 用户定义的函数来拆分字符串,那么有相当不错的字符串操作方法。您可以使用以下字符串并对每个搜索词应用 String.Format 方法。除非音量非常大,否则它应该足够快,甚至可能如此。

      "(\"{0}*\" OR FORMSOF(THESAURUS, {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();
      }
      

      我会说可能有更有效的方法来实现这一点。

      祝你好运。我希望这会有所帮助。

      【讨论】:

      • 啊,我忘记了 SQL Server 中的 CLR 代码。这实际上似乎是一个非常好的选择,尽管性能有点未知。得再仔细看看……
      猜你喜欢
      • 2017-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多