Existe alguma diferença entre NUMERIC e DECIMAL?

47

Sei que os tipos de dados NUMERIC e DECIMAL no SQL Server funcionam da mesma maneira: a sintaxe para criá-los é a mesma, os intervalos de valores que você pode armazenar neles são os mesmos etc.

No entanto, a documentação do MSDN descreve o relacionamento entre os dois como este:

numérico é funcionalmente equivalente a decimal.

Normalmente, quando vejo o qualificador " funcionalmente equivalente", isso significa que as duas coisas não são exatamente iguais, mas que são dois tipos diferentes que são indistinguíveis do lado de fora .

Essa implicação é verdadeira? Existem diferenças entre NUMÉRICO e DECIMAL que se comportam da mesma forma com um observador externo? Ou eles são realmente equivalentes, por exemplo, NUMERIC é apenas um sinônimo herdado de DECIMAL?

KutuluMike
fonte
1
Você pode encontrar diferenças no suporte fora do SQL Server, por exemplo, acabei de tomar conhecimento dessa estranha diferença no SSIS .
Aaron Bertrand

Respostas:

56

Na verdade, são equivalentes, mas são tipos independentes e não são sinônimos tecnicamente , como ROWVERSIONe TIMESTAMP- embora possam ter sido referidos como sinônimos na documentação ao mesmo tempo . Esse é um significado ligeiramente diferente de sinônimo (por exemplo, eles são indistinguíveis, exceto no nome, nenhum é um apelido para o outro). Irônico, certo?

O que eu interpreto da redação no MSDN é realmente:

Esses tipos são idênticos, eles apenas têm nomes diferentes.

Além dos type_idvalores, tudo aqui é idêntico:

SELECT * FROM sys.types WHERE name IN (N'numeric', N'decimal');

Não tenho absolutamente nenhum conhecimento de diferenças comportamentais entre os dois e, voltando ao SQL Server 6.5, sempre os tratamos como 100% intercambiáveis.

para DECIMAL (18,2) e NUMÉRICO (18,2)? Atribuir um ao outro é tecnicamente uma "conversão"?

Somente se você fizer isso explicitamente. Você pode provar isso facilmente criando uma tabela e depois inspecionando o plano de consulta para consultas que executam conversões explícitas ou - você pode esperar - implícitas. Aqui está uma tabela simples:

CREATE TABLE [dbo].[NumDec]
(
    [num] [numeric](18, 0) NULL,
    [dec] [decimal](18, 0) NULL
);

Agora execute essas consultas e capture o plano:

DECLARE @num NUMERIC(18,0);
DECLARE @dec DECIMAL(18,0);

SELECT 
  CONVERT(DECIMAL(18,0), [num]), -- conversion
  CONVERT(NUMERIC(18,0), [dec])  -- conversion
FROM dbo.NumDec
UNION ALL SELECT [num],[dec] 
  FROM dbo.NumDec WHERE [num] = @dec  -- no conversion
UNION ALL SELECT [num],[dec] 
  FROM dbo.NumDec WHERE [dec] = @num; -- no conversion

Conforme mostrado no SQL Sentry Plan Explorer *, o plano não é realmente interessante:

insira a descrição da imagem aqui

Mas a guia Expressões com certeza é:

insira a descrição da imagem aqui

Como comentei acima, temos conversões explícitas onde pedimos, mas não há conversões explícitas onde poderíamos tê-las esperado. Parece que o otimizador também os está tratando como intercambiáveis.

Vá em frente e tente este teste também (dados e índices).

CREATE TABLE [dbo].[NumDec2]
(
    [num] [numeric](18, 2) NULL,
    [dec] [decimal](18, 2) NULL
);

INSERT dbo.NumDec2([num],[dec])
SELECT [object_id] + 0.12, [object_id] + 0.12
  FROM sys.all_columns;

CREATE INDEX [ix_num] ON dbo.NumDec2([num]);
CREATE INDEX [ix_dec] ON dbo.NumDec2([dec]);

Agora execute esta consulta:

DECLARE @num NUMERIC(18,2) = -1291334356.88,
        @dec NUMERIC(18,2) = -1291334356.88;

SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = @num
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = @dec;

O plano não possui conversões (na verdade, a guia Expressões está vazia):

insira a descrição da imagem aqui

Mesmo estes não levam a conversões inesperadas. É claro que você o vê no RHS no predicado, mas em nenhum caso ocorreu nenhuma conversão nos dados da coluna para facilitar a busca (muito menos forçar uma varredura).

SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(DECIMAL(18,2), @num)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(DECIMAL(18,2), @dec)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(NUMERIC(18,2), @num)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(NUMERIC(18,2), @dec)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(DECIMAL(18,2), @num)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(DECIMAL(18,2), @dec)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(NUMERIC(18,2), @num)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(NUMERIC(18,2), @dec);

Pessoalmente, prefiro usar o termo DECIMALapenas porque é muito mais preciso e descritivo. BITtambém é "numérico".

* Disclaimer: I work for SQL Sentry.
Aaron Bertrand
fonte
Eu sei que o SQL trata, por exemplo, DECIMAL (18,2) e DECIMAL (18,0) como "tipos diferentes"; isso significa o mesmo para DECIMAL (18,2) e NUMERIC (18,2)? Atribuir um ao outro é tecnicamente uma "conversão"?
precisa saber é o seguinte
@MichaelEdenfield Atualizei minha resposta para sua nova pergunta.
Aaron Bertrand
1
Sei que essa é uma resposta antiga, mas acabei de encontrar um caso em que pensar que numérico e decimal são sinônimos, causou um erro no SQL Server. Apenas pensei em deixar um comentário aqui, caso outra pessoa possa se beneficiar.
Zohar Peled
@AaronBertrand Votei na sua resposta porque é útil. Ambos os tipos parecem idênticos; se for esse o caso, por que eles são nomeados de maneira diferente? existe alguma razão histórica ?
Ivanzinho
@ Ivanzinho Eu não tenho certeza se sua pergunta é retórica, existem várias teorias (nesta página e na resposta que você vinculou), mas se você quiser uma resposta definitiva, provavelmente estará sem sorte. Você precisaria rastrear os engenheiros originais que primeiro implementaram os dois tipos no SQL Server e confiar na memória deles da implementação e na interpretação do padrão naquele momento.
Aaron Bertrand
15

Eles são idênticos na prática, no entanto (do padrão SQL 2003):

21) NUMERIC especifica o tipo de dados numérico exato, com a precisão decimal e a escala especificadas por precisione scale.

22) DECIMAL especifica o tipo de dados numérico exato, com a escala decimal especificada pela precisão decimal definidascale pela implementação e igual ou maior que o valor especificado precision.

Neil McGuigan
fonte
5
A questão fundamental, então (e acredito que a resposta é não), o SQL Server implementou a precisão do DECIMAL de maneira diferente da NUMERIC? O que o padrão diz que poderia ser feito é muito menos relevante do que o que realmente foi feito.
Aaron Bertrand
5
Obrigado. Essa é uma excelente resposta para a pergunta de acompanhamento de por que existem dois tipos com nomes diferentes, mas com comportamento idêntico.
Gabe