Estou executando o SQL Server 2012
SELECT
0.15 * 30 / 360,
0.15 / 360 * 30
Resultados:
0.012500,
0.012480
Este é até mais confuso para mim:
DECLARE @N INT = 360
DECLARE @I DECIMAL(38,26) = 0.15 * 30 / 360
DECLARE @C DECIMAL(38,26) = 1000000
SELECT @C * @I * POWER(1 + @I, @N) / ( POWER(1 + @I, @N) - 1 )
SELECT @C * (@I * POWER(1 + @I, @N) / ( POWER(1 + @I, @N) - 1 ) )
A primeira seleção fornece o resultado correto: 12644.44022 A segunda trunca o resultado: 12644.00000
sql-server
sql-server-2012
t-sql
decimal
cpacheco
fonte
fonte
Respostas:
Determinar a precisão e a escala resultantes das expressões é um ninho de ratos e eu não acho que alguém entenda as regras exatas em todos os cenários, especialmente ao misturar decimal (ou float!) E int. Veja esta resposta por gbn .
Obviamente, você pode adaptar as expressões para fornecer o que deseja, fazendo conversões explícitas muito mais detalhadas. Provavelmente é um exagero, mas:
Nenhum dos resultados é arredondado incorretamente devido à matemática de ponto flutuante quebrada ou à precisão / escala totalmente erradas.
fonte
Como Aaron Bertrand mencionou, as expressões são muito difíceis de prever.
Se você se atreve a ir para lá, pode tentar obter algumas dicas usando o seguinte snippet:
Este é o resultado:
fonte
Não obstante as excelentes respostas já adicionadas a esta pergunta, há uma ordem de precedência explicitamente definida para a conversão de tipos de dados no SQL Server.
Quando um operador combina duas expressões de tipos de dados diferentes, as regras para a precedência do tipo de dados especificam que o tipo de dados com a precedência mais baixa é convertido no tipo de dados com a precedência mais alta. Se a conversão não for uma conversão implícita suportada, um erro será retornado. Quando ambas as expressões de operando têm o mesmo tipo de dados, o resultado da operação possui esse tipo de dados.
O SQL Server usa a seguinte ordem de precedência para tipos de dados:
Assim, por exemplo, se você
SELECT 0.5 * 1
(multiplicando um decimal por um int), obtém um resultado que é convertido em um valor decimal, poisdecimal
é uma precedência mais alta que oint
tipo de dados.Consulte http://msdn.microsoft.com/en-us/library/ms190309.aspx para obter mais detalhes.
Dito tudo isso, provavelmente
SELECT @C * (@I * POWER(1 + @I, @N) / (POWER(1 + @I, @N) - 1 ));
deve retornar um valor decimal, pois praticamente todas as entradas são decimais. Curiosamente, você pode forçar um resultado correto modificando issoSELECT
para:Isso retorna:
Não consigo explicar como isso faz alguma diferença, embora claramente faça . Meu palpite é que
1E0
(uma flutuação explícita) naPOWER(
função força o SQL Server a fazer uma escolha diferente nos tipos de saída para aPOWER
função. Se minha suposição estiver correta, isso indicaria um possível bug naPOWER
função, uma vez que a documentação indica que a primeira entradaPOWER()
é float ou um número que pode ser implicitamente convertido em float.fonte
Você está familiarizado com a
SELECT .. INTO
sintaxe ? É um truque útil para desconstruir situações como essa, porque cria uma tabela em tempo real com apenas os tipos de dados corretos para aSELECT
lista fornecida .Você pode dividir seu cálculo em suas etapas constituintes, aplicando as regras de precedência dos SQL Servers à medida que avança, para ver como a definição é alterada. Aqui está como seu primeiro exemplo seria:
Esta é a saída:
fonte
(1+1)
e2
são do tipo,int
mas esta questão tem um exemplo em que eles acabam produzindo um resultado de tipo diferente.