2010-10-11 17 views
5

Ho una tabella aziende con una colonna CompanyName multilingue (definita come nvarchar (512)).Ordinamento di una colonna rispetto a regole di confronto differenti in SQL Server

Ho anche una stored procedure per cercare e restituire un elenco di aziende, ci vogliono 2 parametri nvarchar - uno è il termine di ricerca, e l'altro è un codice di lingua ISO.

Quello che mi piacerebbe essere in grado di fare è restituire i risultati della ricerca ordinato con un confronto appropriato per il codice della lingua fornito nel secondo parametro, ad esempio:

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 

tuttavia ricevo il seguente errore quando provo a lanciarlo:

non riesce a risolvere il conflitto di confronto tra "Chinese_Simplified_Pinyin_100_CI_AI" e "Sami_Sweden_Finland_100_CI_AI" in t l'operazione CASE.

Questo non ha senso per me - non è come sto ordinando attraverso le regole di confronto, perché ci sarebbe un conflitto di confronto? È una scelta reciprocamente esclusiva.

Ho cercato di non essere troppo intelligente e di usare solo SQL dinamico, sfortunatamente sembra che il database non sia in grado di memorizzare nella cache un piano di esecuzione, quindi i tempi di interrogazione sono in aumento di 20 secondi (rispetto a 1) quando la tabella contiene circa 2 milioni di righe.

Sono sicuro che l'ordinamento sensibile alla cultura deve essere un problema comune, qualcuno sa di una buona soluzione che non comporta la modifica dello schema corrente (ad esempio, come dover creare colonne aggiuntive)?

risposta

2

Acolumn può avere solo una fascicolazione. Il miso CASE che stai cercando di avere multipli che sono in conflitto tra loro. Prova questo:

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

Grazie, questo nega la necessità di utilizzare SQL dinamico (anche se sono ancora confuso sul perché le diverse regole di confronto in una singola istruzione CASE causino un conflitto - sarà sempre solo su uno!). Il problema ora è che SQL non sembra raccogliere gli indici come parte del piano di esecuzione. Nell'esempio precedente ho creato 2 colonne calcolate (indicizzate) nella colonna CompanyName con le collation svedesi e Pinyin, rispettivamente, che vengono rilevate quando si esegue un ORDER BY CompanyName con un confronto esplicito, ma non nella query precedente. Se c'è un modo per dire esplicitamente a SQL di usare gli indici? –

+0

@ Jonathan Hoult: sfortunatamente no. L'indice è invalidato dalla clausola COLLATE come ci si aspetterebbe. – gbn

2

Ok ho finalmente elaborato la risposta a questo, grazie alla @gbn, la soluzione è stata sicuramente corrette fornite mia definizione iniziale della domanda.

Tuttavia risulta che stavo lavorando sotto l'assunto errato che Dynamic SQL dovrebbe essere evitato. Per arrivare a questo lavoro ho dovuto aggiungere una colonna calcolata (e indicizzato) con un valore di

CompanyName COLLATE [Collation_Name] 

per ogni collazione avevo bisogno di ordinare il (mi rendo conto che ho detto nella mia domanda iniziale che non volevo per modificare lo schema, ma quello che volevo dire era che non volevo spostare i dati esistenti).

Quando si esegue la seguente query

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

il motore di query preleva l'indice nella colonna calcolata associato e ottenere una risposta veloce. Sfortunatamente quando si utilizza la query fornita da @gbn, gli indici creati sulle colonne calcolate vengono ignorati, con un conseguente impatto sulle prestazioni.

Questo è tutto molto sorprendente per me come ho sempre creduto che Dynamic SQL è un male che dovrebbe essere evitato a meno che assolutamente necessario (I.e quando la tua query varia in modo da non poter essere parametrizzata)

Problemi correlati