Surgiu a seguinte dúvida no trabalho esse dias que foi mais ou menos assim:
Tenho duas colunas e estou realizando uma divisão entre elas. Qual vai ser o tipo retornado? O SQL Server segue a ordem de precedência do tipo do dado?
De bate pronto, a resposta é um “Sim, ele sempre vai seguir a ordem de precedência e vai retornar o tipo de dado que você está usando que possui maior precedência.”
Porém (sempre tem um porém), isso não é valido para os tipos decimais.
Para entender isso, precisamos entender três conceitos nos tipo de dados: Tamanho (length), precisão (precision) e escala (scale).
Quando você executar um ‘sp_help TB_Decimal’ (a.k.a. “ALT+F1 na tabela”), você vai ver três colunas:
– Length: quando falamos de tipos numéricos, ele retrata o tamanho em bytes que a coluna vai ocupar. Quando é um tipo texto ((n)char, (n)varchar) é a quantidade de caracteres.
– Prec: Quantidade de digitos em um número (111 = precisão de 3, 111.22 = precisão de 5).
– Scale: Quantidade de dígitos nas casas decimais (111 = escala com 0 dígitos, 111.22 = escala com 2 dígitos)
Obs: A precisão que você usar, vai mudar o tamanho que você verá no length.
1 2 3 4 5 |
Precisão Espaço (bytes) 1-9 5 10-19 9 <-- A que eu usei no exemplo! 20-28 13 29-38 17 |
Veja o exemplo abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
CREATE TABLE TB_DECIMAL (valor1 decimal(15,2), valor2 int, valor3 decimal(15,2)) INSERT INTO TB_DECIMAL VALUES (50,10,10) select valor1, valor2, valor3, VALOR1/valor2, valor1/10, valor1/cast(10 as decimal(15,2)), valor1/valor3, 50.00/valor2, 50.00/10, 50/10 FROM TB_DECIMAL |
Note que até para a divisão entre dois números decimais, ele não seguiu as casas decimais especificadas na tabela.
Vamos ver como o cálculo é feito (e aqui, seremos bem teóricos), usando a divisão do tipo decimal por um inteiro (valor1 / valor2), alinhando que cada coluna é uma expressão (chamada aqui de ‘e’), que possui uma precisão (‘p’) e uma escala (‘s’).
Dessa forma, temos que:
Valor1 = e1, com precisão p1 e escala s1
Valor2 = e2, com precisão p2 e escala s2
As fórmulas para o calculo da precisão e da escala para a divisão são:
Precisão
p1 – s1 + s2 + max(6, s1 + p2 + 1)
15 – 2 + 0 + max(6, 2 + 10 +1)
13 + max(6, 13)
13 + 13
26
Escala:
max(6, s1 + p2 + 1)
max(6, 2 + 10 + 1)
max(6, 13)
13
O resultado da consulta foi 5.0000000000000, fechando com os 13 dígitos que tivemos na escala. Poderíamos ainda ter um número onde a divisão teria como resultado mais de 13 dígitos significativos para que ele não desse overflow.
Vamos ver agora a questão do decimal / decimal
Precisão:
p1 – s1 + s2 + max(6, s1 + p2 + 1)
15 – 2 + 2 + max(6, 2 + 15 +1)
15 + max(6, 118)
15 + 18
33Escala
max(6, s1 + p2 + 1)
max(6, 2 + 15 + 1)
max(6, 18)
18
Resultado da consulta: 5.000000000000000000.
TL/DR: Quando for realizar uma operação onde o resultado será um tipo decimal, prepare-se para tratar as casas decimais. 🙂
Fontes:
Para saber mais sobre as fórmulas de cálculo para as demais operações, veja em:
https://docs.microsoft.com/en-us/sql/t-sql/data-types/precision-scale-and-length-transact-sql
Para saber a ordem de precedência de dados
https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-precedence-transact-sql