Работа со строками SQL Server - разделение поисковых терминов и создание новой строки - PullRequest
0 голосов
/ 10 мая 2011

В настоящее время я создаю функцию поиска на основе полнотекстового индекса 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))'

Очевидно, что если бы в пользовательском вводе было три слова, было бы три набора терминов «подстановочный знак ИЛИ тезаурус ИЛИ инфлективный».

Будучи новичком в T-SQL (не новичком, но, конечно, не гуру!), Я не уверен в том, как лучше это сделать. Я гуглил, и, хотя я сталкивался с вещами, которые могли бы помочь с первоначальным разбиением строки, я не совсем понял, как лучше всего использовать это разделенное представление для создания результирующей строки.

Может кто-нибудь помочь, пожалуйста?

Ответы [ 2 ]

1 голос
/ 10 мая 2011

Существуют довольно хорошие методы манипуляции со строками, если вы используете пользовательскую функцию SQLCLR, чтобы разбить строку. Вы можете использовать следующую строку и применить метод String.Format для каждого поискового запроса. Он должен быть достаточно быстрым, если нет слишком большого объема, и, возможно, даже тогда.

"(\" {0} * \ "ИЛИ FORMSOF (ТЕЗАУРУС, {0}) ИЛИ FORMSOF (ИНФЛЕКЦИОНАЛЬНЫЙ, {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();
}

Я скажу, что могут быть более эффективные средства для достижения этой цели.

Удачи. Надеюсь, это поможет.

1 голос
/ 10 мая 2011

Я не знаю, будет ли это наиболее эффективным подходом к вашей проблеме, но одна мысль, которая приходит в голову, заключается в инкапсуляции логики для разбиения входной строки в табличную функцию.

Вызовите функцию и сохраните результаты в табличной переменной.

Переберите переменную таблицы и объедините разделенные строки в последнюю строку, которую вы будете использовать для поиска.

Я не включил здесь код функции (для краткости), но в моем случае моя функция принимает строку для разделения и разделитель для строки и возвращает таблицу со следующей структурой: 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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...