Existe-t-il une différence entre NUMERIC et DECIMAL?

47

Je sais que les types de données NUMERIC et DECIMAL dans SQL Server fonctionnent de la même manière: la syntaxe pour les créer est la même, les plages de valeurs que vous pouvez y stocker sont les mêmes, etc.

Cependant, la documentation MSDN décrit la relation entre les deux comme ceci:

numeric est fonctionnellement équivalent à décimal.

Normalement, lorsque je vois le qualificatif " fonctionnellement équivalent", cela signifie que les deux choses ne sont pas exactement identiques, mais qu'il s'agit de deux types différents qui ne peuvent pas être distingués de l'extérieur .

Cette implication est-elle vraie? Existe-t-il des différences entre NUMERIC et DECIMAL qui se comportent de la même manière vis-à-vis d'un observateur extérieur? Ou sont-ils réellement équivalents, par exemple NUMERIC est-il simplement un synonyme hérité de DECIMAL?

KutuluMike
la source
1
Vous pouvez trouver des différences de support en dehors de SQL Server, par exemple, je viens d’être informé de cette différence étrange dans SSIS .
Aaron Bertrand
stackoverflow.com/questions/1056323/…
Shiwangini Shishulkar le

Réponses:

56

Ils sont en fait équivalents, mais ce sont des types indépendants, et non techniquement synonymes, comme ROWVERSIONet TIMESTAMP- bien qu'ils aient été appelés synonymes dans la documentation à la fois . C’est une signification légèrement différente de synonyme (par exemple, ils ne peuvent être distingués que par leur nom, aucun n’est un alias pour l’autre). Ironique, non?

Ce que j’interprète à partir du libellé de MSDN est en réalité:

Ces types sont identiques, ils ont juste des noms différents.

Autre que les type_idvaleurs, tout est identique ici:

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

Je ne connais absolument aucune différence de comportement entre les deux. Pour revenir à SQL Server 6.5, je les ai toujours traitées comme interchangeables à 100%.

pour DECIMAL (18,2) et NUMERIC (18,2)? Assigner l'un à l'autre est techniquement une "conversion"?

Seulement si vous le faites explicitement. Vous pouvez facilement le prouver en créant une table, puis en inspectant le plan de requête pour rechercher les requêtes qui effectuent des conversions explicites ou implicites. Voici un tableau simple:

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

Maintenant, lancez ces requêtes et capturez le plan:

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

Comme indiqué dans SQL Sentry Plan Explorer *, le plan n’est pas vraiment intéressant:

entrez la description de l'image ici

Mais l'onglet Expressions est bien sûr:

entrez la description de l'image ici

Comme je l'ai mentionné ci-dessus, nous avons des conversions explicites où nous les avons demandées, mais pas de conversions explicites où nous aurions pu les attendre. Il semble que l’optimiseur les traite également comme interchangeables.

Allez-y et essayez ce test aussi (données et index).

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]);

Maintenant, lancez cette requête:

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;

Plan n'a aucune conversion (en fait, l'onglet Expressions est vide):

entrez la description de l'image ici

Même ceux-ci ne conduisent à aucune conversion inattendue. Bien sûr, cela se voit sur le RHS dans le prédicat, mais dans aucun cas, aucune conversion ne doit avoir lieu contre les données de colonne pour faciliter la recherche (et encore moins forcer une analyse).

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);

Personnellement, je préfère utiliser le terme DECIMALsimplement parce qu'il est beaucoup plus précis et descriptif. BITest "numérique" aussi.

* Disclaimer: I work for SQL Sentry.
Aaron Bertrand
la source
Je sais que SQL traite, par exemple, DECIMAL (18,2) et DECIMAL (18,0) en tant que "types différents"; Est-ce que cela signifie la même chose pour DECIMAL (18,2) et NUMERIC (18,2)? Assigner l'un à l'autre est techniquement une "conversion"?
KutuluMike
@ MichaelEdenfield Mis à jour ma réponse pour votre nouvelle question.
Aaron Bertrand
1
Je sais que cette réponse est ancienne, mais je viens de trouver un cas où penser que numérique et décimal sont des synonymes a provoqué une erreur de la part de SQL Server. Je pensais juste que je devrais laisser un commentaire ici au cas où quelqu'un d'autre en profiterait.
Zohar Peled
@AaronBertrand J'ai voté pour votre réponse car elle est utile. Les deux types semblent identiques, alors si c'est le cas, pourquoi sont-ils nommés différemment? Y a-t-il une raison historique ?
Ivanzinho
@ Ivanzinho Je ne sais pas si votre question est rhétorique, il y a beaucoup de théories (à la fois sur cette page et sur la réponse que vous avez liée), mais si vous voulez une réponse définitive, vous n'aurez probablement pas de chance. Vous devez rechercher les ingénieurs d'origine qui ont initialement implémenté les deux types dans SQL Server et vous fier à leur mémoire de cette implémentation et à leur interprétation de la norme à ce moment-là.
Aaron Bertrand
15

Ils sont toutefois identiques dans la pratique (à partir du standard SQL 2003):

21) NUMERIC spécifie le type de données numeric exact, avec la précision décimale et l’échelle spécifiées par les precisionet scale.

22) DECIMAL spécifie le type de données numérique exact, avec l’échelle décimale spécifiée par le scaleet la précision décimale définie par l’ implémentation égale ou supérieure à la valeur spécifiée precision.

Neil McGuigan
la source
5
La question fondamentale alors (et je pense que la réponse est non), est-ce que SQL Server a implémenté la précision de DECIMAL différemment de celle de NUMERIC. Ce que la norme dit pouvoir faire est beaucoup moins pertinent que ce qui a été fait.
Aaron Bertrand
5
Merci. C’est une excellente réponse à la question suivante, à savoir pourquoi il existe deux types avec des noms différents mais un comportement identique.
Gabe