Gibt es überhaupt einen Unterschied zwischen NUMERIC und DECIMAL?

47

Ich weiß, dass die Datentypen NUMERIC und DECIMAL in SQL Server gleich funktionieren: Die Syntax für deren Erstellung ist dieselbe, die Wertebereiche, die Sie in ihnen speichern können, sind dieselbe usw.

Die MSDN-Dokumentation beschreibt jedoch die Beziehung zwischen den beiden wie folgt:

numerisch ist funktional äquivalent zu dezimal.

Wenn ich das Qualifikationsmerkmal " funktional äquivalent" sehe , bedeutet dies normalerweise, dass die beiden Dinge nicht genau gleich sind, sondern dass es sich um zwei verschiedene Typen handelt, die von außen nicht zu unterscheiden sind .

Ist diese Implikation wahr? Gibt es Unterschiede zwischen NUMERIC und DECIMAL, die sich für einen externen Beobachter zufällig gleich verhalten? Oder sind sie tatsächlich gleichwertig, zB ist NUMERIC nur ein Synonym für DECIMAL?

KutuluMike
quelle
1
Möglicherweise finden Sie Unterschiede in der Unterstützung außerhalb von SQL Server. Ich wurde beispielsweise gerade auf diesen merkwürdigen Unterschied in SSIS aufmerksam gemacht .
Aaron Bertrand

Antworten:

56

Sie sind eigentlich äquivalent, aber sie sind unabhängige Typen und keine technischen Synonyme, wie ROWVERSIONund TIMESTAMP- obwohl sie in der Dokumentation möglicherweise zu einem Zeitpunkt als Synonyme bezeichnet wurden . Das ist eine etwas andere Bedeutung von Synonym (z. B. sind sie nicht unterscheidbar, außer im Namen, nicht einer ist ein Alias ​​für den anderen). Ironisch, richtig?

Was ich aus dem Wortlaut in MSDN interpretiere, ist tatsächlich:

Diese Typen sind identisch, sie haben nur unterschiedliche Namen.

Abgesehen von den type_idWerten ist hier alles identisch:

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

Ich habe absolut keine Kenntnis von irgendwelchen Verhaltensunterschieden zwischen den beiden und gehe zurück auf SQL Server 6.5, habe sie immer als 100% austauschbar behandelt.

für DECIMAL (18,2) und NUMERIC (18,2)? Eine Zuordnung zu einer anderen ist technisch eine "Umstellung"?

Nur wenn Sie dies ausdrücklich tun. Sie können dies auf einfache Weise beweisen, indem Sie eine Tabelle erstellen und dann den Abfrageplan auf Abfragen untersuchen, die explizite oder - wie Sie vielleicht erwarten - implizite Konvertierungen ausführen. Hier ist eine einfache Tabelle:

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

Führen Sie nun diese Abfragen aus und erfassen Sie den 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

Wie im SQL Sentry Plan Explorer * gezeigt, ist der Plan nicht wirklich interessant:

Bildbeschreibung hier eingeben

Aber die Registerkarte Ausdrücke ist sicher:

Bildbeschreibung hier eingeben

Wie ich oben ausgeführt habe, haben wir explizite Conversions, bei denen wir darum gebeten haben, aber keine expliziten Conversions, bei denen wir sie erwartet hätten. Scheint, dass der Optimierer sie auch als austauschbar behandelt.

Probieren Sie auch diesen Test aus (Daten und Indizes).

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

Führen Sie nun diese Abfrage aus:

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 hat keine Conversions (die Registerkarte "Ausdrücke" ist leer):

Bildbeschreibung hier eingeben

Auch diese führen zu keinen unerwarteten Konvertierungen. Natürlich sehen Sie es auf der rechten Seite im Prädikat, aber in keinem Fall musste eine Konvertierung für die Spaltendaten durchgeführt werden, um die Suche zu erleichtern (viel weniger erzwingen Sie einen Scan).

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

Ich persönlich bevorzuge es, den Begriff DECIMALnur zu verwenden, weil er viel genauer und aussagekräftiger ist. BITist auch "numerisch".

* Disclaimer: I work for SQL Sentry.
Aaron Bertrand
quelle
Ich weiß, dass SQL zB DECIMAL (18,2) und DECIMAL (18,0) als "verschiedene Typen" behandelt; Bedeutet dies dasselbe für DECIMAL (18,2) und NUMERIC (18,2)? Eine Zuordnung zu einer anderen ist technisch eine "Umstellung"?
KutuluMike
@MichaelEdenfield Meine Antwort auf Ihre neue Frage wurde aktualisiert.
Aaron Bertrand
1
Ich weiß, dass dies eine alte Antwort ist, aber ich habe gerade einen Fall gefunden, in dem der Gedanke, dass numerisch und dezimal Synonyme sind, SQL Server dazu veranlasste, einen Fehler auszulösen. Ich dachte nur, ich sollte hier einen Kommentar hinterlassen, falls jemand anderes davon profitieren könnte.
Zohar Peled
@ AaronBertrand Ich habe für Ihre Antwort gestimmt, weil es hilfreich ist. Beide Typen scheinen identisch zu sein. Wenn dies der Fall ist, warum werden sie dann unterschiedlich benannt? Gibt es einen historischen Grund ?
Ivanzinho
@Ivanzinho Ich bin mir nicht sicher, ob Ihre Frage rhetorisch ist, es gibt eine Reihe von Theorien (sowohl auf dieser Seite als auch auf der Antwort, die Sie verlinkt haben), aber wenn Sie eine endgültige Antwort wünschen, werden Sie wahrscheinlich Pech haben. Sie müssten die ursprünglichen Ingenieure ausfindig machen, die beide Typen zuerst in SQL Server implementiert haben, und sich auf ihre Erinnerung an diese Implementierung und ihre Interpretation des Standards zu diesem Zeitpunkt verlassen.
Aaron Bertrand
15

Sie sind jedoch in der Praxis identisch (ab SQL 2003-Standard):

21) Numerischer gibt den Datentyp exakte numerische, mit dem Dezimalsystem und Dezimalstellenwerte spezifiziert durch die precisionund scale.

22) DECIMAL gibt den Datentyp genau numerisch an, wobei die durch die scaleund die implementierungsdefinierte Dezimalgenauigkeit angegebene Dezimalskala gleich oder größer als der angegebene Wert ist precision.

Neil McGuigan
quelle
5
Die grundlegende Frage damals (und ich glaube, die Antwort lautet nein): Hat SQL Server die DECIMAL-Genauigkeit anders implementiert als die von NUMERIC? Was laut Norm getan werden könnte , ist weitaus weniger relevant als das, was tatsächlich getan wurde.
Aaron Bertrand
5
Vielen Dank. Dies ist eine hervorragende Antwort auf die Frage, warum es zwei Typen mit unterschiedlichen Namen, aber identischem Verhalten gibt.
Gabe