2010-10-11 22 views
5

Mam tabelę Companies z wielojęzyczną kolumną CompanyName (zdefiniowaną jako nvarchar (512)).Sortowanie kolumny przed różnymi sortowaniami w SQL Server

Mam również procedurę przechowywaną do przeszukiwania i zwracania listy firm, wymaga ona dwóch parametrów nvarchar - jeden jest terminem wyszukiwania, a drugi jest kodem języka ISO.

Co chciałbym być w stanie zrobić, to wrócić wyniki wyszukiwania posortowane z zestawień odpowiedniej dla kodu języka dostarczonym w drugim parametrem, na przykład:

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 

jednak pojawia się następujący błąd przy próbie uruchomienia go:

nie można rozwiązać konflikt sortowania między „Chinese_Simplified_Pinyin_100_CI_AI” i „Sami_Sweden_Finland_100_CI_AI” w t operacja CASE.

To nie ma dla mnie żadnego sensu - to nie jest tak, że sortuję w kolekcjach, dlaczego wystąpiłby konflikt kolacjonowania? Jest to wykluczający się wybór.

Próbowałem nie być zbyt sprytny i po prostu używać dynamicznego sql, niestety, wydaje się, że pozostawienie bazy danych nie jest w stanie buforować planu wykonania, dlatego czasy zapytania wynoszą ponad 20 sekund (w przeciwieństwie do 1), gdy tabela zawiera około 2 miliony wierszy.

Jestem pewien, że sortowanie wrażliwe na kulturę musi być powszechnym problemem, czy ktoś wie o dobrym rozwiązaniu, które nie wiąże się z modyfikacją obecnego schematu (np. Jak utworzyć dodatkowe kolumny)?

Odpowiedz

2

Acolumn może mieć tylko jedno uporządkowanie. Pomysł CASE, który próbujesz mieć wiele konfliktów ze sobą. Spróbuj tego:

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

Dzięki temu neguje to potrzebę korzystania z dynamicznego SQL (chociaż wciąż nie rozumiem, dlaczego różne zestawienia w jednym przypadku CASE spowodowałyby konflikt - będzie to tylko jeden na sobie!). Problem polega na tym, że SQL nie wydaje się przechwytywać indeksów jako części planu wykonania. W powyższym przykładzie utworzyłem 2 kolumny obliczeniowe (indeksowane) odpowiednio w kolumnie NazwaFirmy, odpowiednio ze zbiorem szwedzkim i Pinyin, które są pobierane podczas wykonywania ZAMÓWIENIA PRZEZ FirmName z wyraźnym zestawieniem, ale nie w powyższym zapytaniu. Czy istnieje sposób jawnego wskazania SQL do korzystania z indeksów? –

+0

@ Jonathan Hoult: niestety, nie. Indeks jest unieważniany przez klauzulę COLLATE, jak można się spodziewać. – gbn

2

Ok mam w końcu wypracować odpowiedź na to, dzięki @gbn, rozwiązanie zdecydowanie poprawiania mój początkowy definicji pytanie.

Jednak okazuje się, że pracowałem pod błędnym założeniem, że należy unikać dynamicznego SQL. Aby uzyskać to do pracy musiałem dodać komputerowej (i indeksowane) kolumnę z wartością

CompanyName COLLATE [Collation_Name] 

dla każdego pęczka I potrzebnego do sortowania na (zdaję sobie sprawę, że w moim oryginalne pytanie, że nie chcą zmienić schemat, ale naprawdę chciałem powiedzieć, że nie chciałem przenosić istniejących danych).

Uruchamiając następujące zapytanie

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

silnik kwerendy podnosi indeks na kolumnie komputerowej związanej i uzyskać szybką odpowiedź. Niestety podczas korzystania z zapytania udostępnionego przez @ gbn indeksy utworzone w kolumnach obliczeniowych są ignorowane, co powoduje trafienie wydajności.

To wszystko jest dla mnie bardzo zaskakujące, ponieważ zawsze uważałem, że Dynamiczny SQL jest złem, którego należy unikać, chyba że jest to absolutnie konieczne (i.e gdy zapytanie zmienia się w sposób, którego nie można sparametryzować)