2010-10-11 20 views
5

Tengo una tabla de empresas con una columna CompanyName multilingüe (definida como nvarchar (512)).Ordenar una columna con diferentes intercalaciones en SQL Server

También tengo un procedimiento almacenado para buscar y devolver una lista de empresas, se necesitan 2 parámetros de nvarchar: uno es el término de búsqueda y el otro es un código de idioma ISO.

Lo que me gustaría ser capaz de hacer es devolver los resultados de la búsqueda ordenados con una intercalación adecuada para el código de idioma suministrado en el segundo parámetro, por ejemplo:

SELECT * FROM dbo.Companies WHERE CompanyName LIKE '%searchstring%' 
ORDER BY 
    CASE @lang 
     WHEN 'sv' THEN CompanyName COLLATE Sami_Sweden_Finland_100_CI_AI 
     WHEN 'ch' THEN CompanyName COLLATE Chinese_Simplified_Pinyin_100_CI_AI 
       ELSE CompanyName 
    END 

sin embargo me sale el siguiente de error cuando intento ejecutarlo:

no puede resolver el conflicto de intercalación entre "Chinese_Simplified_Pinyin_100_CI_AI" y "Sami_Sweden_Finland_100_CI_AI" en t la operación CASE.

Esto no tiene sentido para mí, no es como si estuviera ordenando las intercalaciones, ¿por qué habría un conflicto de intercalación? Es una elección mutuamente exclusiva.

He intentado no ser demasiado inteligente y usar sql dinámico, desafortunadamente que parece estar saliendo de la base de datos incapaz de almacenar en caché un plan de ejecución, por lo tanto los tiempos de consulta toman más de 20 segundos (en lugar de 1) cuando la tabla contiene alrededor de 2 millones de filas.

Estoy seguro de que la clasificación sensible a la cultura debe ser un problema común, ¿alguien sabe de una buena solución que no implique alterar el esquema actual (es decir, tener que crear columnas adicionales)?

Respuesta

2

Acolumn solo puede tener una intercalación. El CASO demuestra que estás tratando de tener múltiples conflictos entre ellos. Prueba esto:

SELECT * FROM dbo.Companies WHERE CompanyName LIKE '%searchstring%' 
ORDER BY 
    CASE @lang 
     WHEN 'sv' THEN CompanyName ELSE '' END 
    END COLLATE Sami_Sweden_Finland_100_CI_AI, 
    CASE @lang 
     WHEN 'ch' THEN CompanyName ELSE '' END 
    END Chinese_Simplified_Pinyin_100_CI_AI 
+0

Gracias, esto niega la necesidad de utilizar SQL dinámico (aunque todavía estoy confundido de por qué diferentes intercalaciones en una sola declaración CASE causarían un conflicto - ¡solo ordenará en uno!). El problema ahora es que SQL no parece recoger los índices como parte del plan de ejecución. En el ejemplo anterior he creado 2 columnas calculadas (indexadas) en la columna CompanyName con colaciones suecas y pinyin, respectivamente, que se recogen al hacer un ORDER BY CompanyName con una intercalación explícita, pero no en su consulta anterior. ¿Hay alguna manera de decirle explícitamente a SQL que use los índices? –

+0

@Jonathan Hoult: desafortunadamente, no. El índice está invalidado por la cláusula COLLATE como es de esperar. – gbn

2

bien por fin he trabajado a cabo la respuesta a esto, gracias a @gbn, su solución sin duda era correcto dado mi definición inicial de la cuestión.

Sin embargo, resulta que estaba trabajando bajo la suposición equivocada de que se debe evitar el SQL dinámico. Para conseguir esto para trabajar he tenido que añadir una columna calculada (e indexados) con un valor de

CompanyName COLLATE [Collation_Name] 

para cada cotejo que necesitaba para ordenar (Me doy cuenta de que dije en mi pregunta original que no quería para alterar el esquema, pero lo que realmente quería decir es que no quería mover los datos existentes).

Cuando se ejecuta la siguiente consulta

EXEC('SELECT TOP 10 * FROM dbo.Companies 
     WHERE CompanyName LIKE ''%searchstring%'' 
     ORDER BY CompanyName COLLATE ' + @collation) 

el motor de consulta recoge el índice en la columna calculada asociado y obtener una respuesta rápida. Lamentablemente, al usar la consulta proporcionada por @gbn, los índices creados en las columnas calculadas se ignoran, con el consiguiente golpe de rendimiento.

Esto es muy sorprendente para mí, ya que siempre he creído que el SQL dinámico es un mal que debe evitarse a menos que sea absolutamente necesario (i.e cuando su consulta varía de una manera que no puede parametrizar)

Cuestiones relacionadas