Manipulación de cadenas de SQL Server: división de términos de búsqueda y creación de una nueva cadena

Actualmente estoy construyendo una función de búsqueda basada en índices de texto completo de SQL Server para nuestro sitio y necesito dividir la entrada del usuario en un conjunto de términos de búsqueda. Una vez que los términos se dividen, necesito reconstruirlos en una cadena que contenga la consulta que se ejecutará contra CONTAINS () o una consulta de texto completo CONTAINSTABLE ().

Por ejemplo, si el usuario ingresa

Jon Sidnell

en nuestro cuadro de búsqueda, quiero poder transformar esa cadena en lo siguiente:

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

Obviamente, si hubiera tres palabras en la entrada del usuario, habría tres conjuntos de términos "comodín O tesauro O inflexión".

Siendo un novato en T-SQL (¡no un novato, pero ciertamente no un gurú!) No estoy seguro de cuál es la mejor manera de hacerlo. Busqué en Google, y aunque encontré cosas que ayudarían con la división inicial de la cadena, realmente no tengo ni idea de cómo usar mejor esa representación dividida para construir la cadena resultante.

¿Alguien puede ayudar por favor?

preguntado el 10 de mayo de 11 a las 13:05

2 Respuestas

No sé si este sería el enfoque más eficiente para su problema, pero una idea que me viene a la mente es encapsular la lógica para dividir la cadena de entrada en una función con valores de tabla.

Invoque la función y almacene los resultados en una variable de tabla.

Repita la variable de la tabla y concatene las cadenas divididas en la cadena final que usará para su búsqueda.

No he incluido el código de la función aquí (por brevedad), pero en mi caso, mi función acepta la cadena para dividir y el delimitador para dividir la cadena y devuelve una tabla con la siguiente estructura: Position INT, Value VARCHAR(8000)

Una vez que tenga la función en su lugar, puede incorporarla de manera similar a la siguiente:

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;

La salida debería verse más o menos así:

("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))

contestado el 10 de mayo de 11 a las 20:05

Hay métodos de manipulación de cadenas bastante buenos si utiliza una función definida por el usuario SQLCLR para dividir la cadena. Puede utilizar la siguiente cadena y aplicar el método String.Format para cada término de búsqueda. Debe ser suficientemente rápido a menos que haya un volumen extremadamente alto, y tal vez incluso entonces.

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

Diré que puede haber medios más eficientes para lograrlo.

Buena suerte. Espero que esto ayude.

contestado el 10 de mayo de 11 a las 20:05

Ahhh, me había olvidado del código CLR en SQL Server. Eso en realidad parece una muy buena opción, aunque el rendimiento es un poco desconocido. Tendré que mirar eso un poco más de cerca ... - jonsidnell

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.