2014-09-24 10 views
7

Jestem całkowicie pod drzewem w odniesieniu do sposobu T-SQL obsługuje type precedence z różnymi typami numeric używanych w wyrażeniu CASE. Czy mógłbyś wyjaśnić stosując następujący test:Pierwszeństwo typów numerycznych w T-SQL

-- Consider the query: 
SELECT 
CASE 
     WHEN 1=1 THEN CAST(1.555 AS numeric(16,3)) 
     ELSE CEILING((1+1) * CAST(1 AS Numeric(16,2)) * CAST(1 AS int)) 
END AS Test 
-- This returns 2 (scale = 0) 
-- Now, remove the CEILING function: 
SELECT 
CASE 
     WHEN 1=1 THEN CAST(1.555 AS numeric(16,3)) 
     ELSE (1+1) * CAST(1 AS Numeric(16,2)) * CAST(1 AS int) 
END AS Test 
-- and it gives 1.56 (scale = 2) 
-- Now replace (1+1) with 2: 
SELECT 
CASE 
     WHEN 1=1 THEN CAST(1.555 AS numeric(16,3)) 
     ELSE (2) * CAST(1 AS Numeric(16,2)) * CAST(1 AS int) 
END AS Test 
-- and it yields 1.555 (scale = 3) 

Wydaje mi się źle, ponieważ we wszystkich trzech zapytań numeric(16,3) w 1=1 oddziału powinny mieć pierwszeństwo nad mniej dokładnego wyniku ELSE gałęzi.

+0

Domyślam się, że analizator składni zapytań nie uwzględnia prawdziwej zakodowanej wartości true i ocenia zarówno dla zgodnego typu. Jeśli został wybrany z tabeli, wszystkie zwrócone wartości powinny być tego samego typu. – Paparazzi

+0

@Blam: Wiem, że to nie wyjaśnia, a nawet wtedy wynikowy typ powinien być tym, który ma najwyższy priorytet (zgodnie ze specyfikacją odniesienia operatora CASE), co nie wydaje się być w tym przypadku. –

+0

@Blam: Martwi mnie fakt, że robi * nie * bierze pod uwagę faktycznie wykonywaną gałąź ... –

Odpowiedz

4

Problem polega na tym, że druga gałąź sprawy ma w każdym przypadku inny typ danych.

SELECT CAST(1.555 AS NUMERIC(16, 3))         AS A, 
     CEILING((1 + 1) * CAST(1 AS NUMERIC(16, 2)) * CAST(1 AS INT)) AS B,--NUMERIC(38,0) 
     CAST(1.555 AS NUMERIC(16, 3))         AS C, 
     (1 + 1) * CAST(1 AS NUMERIC(16, 2)) * CAST(1 AS INT)   AS D,--NUMERIC(38,2) 
     CAST(1.555 AS NUMERIC(16, 3))         AS E, 
     (2) * CAST(1 AS NUMERIC(16, 2)) * CAST(1 AS INT)    AS F --NUMERIC(29,2) 
INTO T 

Maksymalna skala numerycznej 38

Pierwszy ma gałąź else NUMERIC(38,0) tak, że jest typu powrotny również. Jeśli inny oddział oceniany na 99999999999999999999999999999999999999, to nic innego nie będzie działać.

Drugi ma jeszcze inny oddział o numerze NUMERIC(38,2), więc ponownie jest to ostatni typ danych z podobnych powodów. Aby zachować dokładność trzech cyfr, musiałby to być NUMERIC(38,3), ale nie zmieściłby się 999999999999999999999999999999999999.99.

Trzeci ma inny oddział: NUMERIC(29,2). To nie jest do maksymalnej 38 skali, więc jest miejsce na nieco rozszerzyć i zachować skalę. Ostateczny typ zwrotu to NUMERIC(30,3).

To oczywiście trochę przesuwa pytanie, dlaczego drugie oddziały oceniają inaczej.

W normalnym toku zdarzeń następujące wyrażenia zrobienia zarówno oceny do int (sprawdź definicję tworzonej tabeli)

SELECT (1 + 1) AS A, 
     (2)  AS B 
INTO T2 

Więc nie ma żadnego oczywistego powodu, dla różniących zachowań pomiędzy tymi dwoma. Ale podejrzewam, że literalne 2 jest traktowane jako NUMERIC(1,0) przez sprawdzenie rzeczywistej wartości.

Podczas gdy nieco bardziej skomplikowane wyrażenie 1 + 1 zostaje potraktowane jako dowolna nieznana liczba całkowita, a jako NUMERIC(10,0).

Następnie można zapoznać się z zasadami szczegółowymi podanymi pod numerem this page w celu zachowania precyzji i skali podczas mnożenia i dzielenia liczb.