2012-08-10 10 views
5

Robię SELECT który wykorzystuje CASE przekonwertować wartości nvarchar do odpowiedniego typu, coś takiego:SPRAWA TO klauzula zawsze oceniana

SELECT CASE 
    WHEN @propType = 'money' THEN convert(money, datavalue) 
    [...] 
    ELSE datavalue 
END 
FROM [...] 

Jednak wydaje się, że convert jest wykonywane zawsze, nawet gdy @propType jest nie równa pieniędzy. Działający przykład:

declare @proptype nvarchar(50)= 'nvarchar' 
declare @val nvarchar(10) = 'test' 
select 
    case @proptype 
     when 'money' then convert(money, @val) 
     else @val 
    end 

Dlaczego tak jest i jak mogę się z nim obejść? W dokumentacji MSDN mówi tak:

Oświadczenie CASE ocenia swoje warunki sekwencyjnie i zatrzymuje z pierwszego warunku, którego warunek jest spełniony. W niektórych sytuacjach wyrażenie jest oceniane przed wykonaniem instrukcji CASE , która otrzymuje wyniki wyrażenia jako dane wejściowe. Błędy w oceny tych wyrażeń są możliwe. Wyrażenia zbiorcze, które pojawiają się w WHEN argumenty do instrukcji CASE są oceniane najpierw, a następnie dostarczone do instrukcji CASE. Na przykład następujące zapytanie powoduje dzielenie przez błąd zerowy przy wytwarzaniu wartości agregatu MAX . Występuje to przed oceną wyrażenia CASE.

Nie jestem pewien, czy to ma znaczenie, ale język jest nieco ciężki dla obcokrajowców, więc może tak jest?

+0

Jedynym celem wyraźnie konwersji '' money' varchar' do kiedy to implicitely przekształcany z powrotem do 'varchar' jest AFAIK tak celom formatowania dlaczego nie można też przechowywać je w wymaganym formatowaniu zacząć z lub pozwolić klientowi obsługiwać formatowanie? –

+1

Dane źródłowe nie są pod moją kontrolą. W rzeczywistości muszę przeskoczyć przez kilka kółek, aby uzyskać dane w takim formacie, że mogę wstawić je do tabeli raportu, do której jest przeznaczone (co jest poprawnie wpisane). – carlpett

Odpowiedz

3

Zapraszamy do obejrzenia poniższego Use caution when Using CONVERT() with CASE or IF functions in Transact SQL (T-SQL)

Pierwsze myśli są zazwyczaj jedną z następujących opcji „Od pierwszego wartość oceniana jest numeryczne, to jest konwertowany na dziesiętne, a wszystkie inne dane oczekuje się być równy dziesiętnie "LUB" Jeśli SQL Server jest w stanie przekonwertować DOWOLNĄ wartość na określony typ, wówczas wszystkie wartości to: , oczekiwane, że są typu przekonwertowanego ". Jednak to nie jest poprawne (chociaż drugi jest blisko)!

Prawdziwym problemem jest to, że jeśli zdecydujesz się przekonwertować wartości gdziekolwiek w case, typ danych konwertowania wartości aby to oczekiwany rodzaj wszystkie wartości, niezależnie od tego, czy są one tego rodzaju lub nie. Ponadto, nawet jeśli NONE z wartości może w rzeczywistości być przekonwertowane (nawet jeśli linia kodu Konwertuj nigdy nie zostanie wykonana), ALL z , to nadal oczekuje się, że wartości będą zgodne z typem określonym przez funkcję konwertowania !

+0

Dzięki, to wyjaśnia dlaczego, ale tak naprawdę nie ma z tego drogi wyjścia? – carlpett

1

Aby być jasne, co dzieje się klauzula then jest nie oceniany.

Widzisz ten sam błąd, jeśli nie

SELECT CASE @proptype 
     WHEN 'money' THEN $1.0 /*<-- Literal of datatype money*/ 
     ELSE @val 
     END 

Dokumentacja CASE wyjaśnia, że ​​zwracany typ

Zwraca najwyższy typ pierwszeństwo z zestawem typów w result_expressions i opcjonalny else_result_expression. Więcej informacji na temat można znaleźć na stronie Data Type Precedence (Transact-SQL).

money ma wyższy priorytet niż typ danych nvarchar więc else @val oceniano wówczas zostanie oddane do money i kończy się niepowodzeniem.

Jednym z możliwych obejść jest przeniesienie go na numer sql_variant, ponieważ ma wyższy priorytet danych niż oba.

declare @proptype nvarchar(50)= 'nvarchar' 
declare @val nvarchar(10) = 'test' 
select 
    case @proptype 
     when 'money' then convert(money, @val) 
     else cast(@val as SQL_VARIANT) 
    end