NUMERIC ve DECIMAL arasında bir fark var mı?


47

SQL Server'daki NUMERIC ve DECIMAL veri türlerinin aynı şekilde çalıştığını biliyorum: bunları oluşturmak için sözdizimi aynı, içinde saklayabileceğiniz değer aralıkları aynı, vb.

Ancak, MSDN belgeleri, ikisi arasındaki ilişkiyi şöyle açıklar:

sayısal, işlevsel olarak ondalık sayıya eşdeğerdir.

Normal olarak, " işlevsel olarak eşdeğer" niteleyicisini gördüğümde , bu iki şeyin tamamen aynı olmadığı , ancak dışarıdan ayırt edilemez iki farklı türde oldukları anlamına gelir .

Bu sonuç doğru mu? NUMERIC ile DECIMAL arasında dışardan bir gözlemciye aynı davranan farklılıklar var mı? Yoksa bunlar aslında eşdeğer mi, örneğin NUMERIC DECIMAL için eski mi bir eşanlamlı?


1
Desteklerde SQL Server dışında farklar bulabilirsiniz , örneğin SSIS'deki bu tuhaf farktan haberdar oldum .
Aaron Bertrand

Yanıtlar:


56

Aslında eşdeğerdirler, ancak bağımsız türlerdir ve teknik olarak eşanlamlılar değildirler , ROWVERSIONve TIMESTAMP- ve bir kerede belgelerde eşanlamlılar olarak adlandırılmış olsalar bile . Bu, eş anlamlılığın biraz farklı bir anlamıdır (örneğin, isim dışında ayırt edilemez, biri diğeri için bir takma ad değildir). İronik değil mi?

MSDN'deki ifadelerden yorumladığım şey aslında:

Bu türler aynı, sadece farklı isimler var.

type_idDeğerler dışında, buradaki her şey aynı:

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

İkisi arasındaki davranış farklılıkları hakkında hiçbir bilgim yok ve SQL Server 6.5'e geri dönüyoruz, onlara her zaman% 100 değiştirilebilir olarak davrandılar.

DECIMAL (18,2) ve NUMERIC (18,2) için mi? Birini diğerine atamak teknik olarak bir "dönüşüm" mü?

Sadece açıkça yaparsan. Bunu bir tablo oluşturarak ve ardından açık veya doğrudan bir sorgulama yapan sorgular için sorgu planını inceleyerek kolayca kanıtlayabilirsiniz. İşte basit bir tablo:

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

Şimdi bu sorguları çalıştırın ve planı yakalayın:

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

SQL Sentry Plan Explorer'da * gösterildiği gibi , plan gerçekten ilginç değil:

görüntü tanımını buraya girin

Ancak İfadeler sekmesi kesinlikle:

görüntü tanımını buraya girin

Yukarıda yorum yaptığım gibi, istediğimiz yerde açıkça dönüşümler yaptık, ancak beklentilerimizi beklediğimiz açıkça bir dönüşüm yok. Optimizer de onlara değişebilir gibi görünüyor.

Devam edin ve bu testi de deneyin (veriler ve dizinler).

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

Şimdi bu sorguyu çalıştırın:

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;

Planda dönüşüm yok (aslında İfadeler sekmesi boş):

görüntü tanımını buraya girin

Bunlar bile beklenmedik dönüşümlere yol açmaz. Tabii ki, bunu RHS'de belirttiğinizde görüyorsunuz, ancak hiçbir durumda arama işlemini kolaylaştırmak için sütun verisine karşı herhangi bir dönüşüm gerçekleşmedi (taramayı çok daha az zorla).

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

Şahsen ben DECIMALsadece daha doğru ve açıklayıcı bir terim olduğu için terimi kullanmayı tercih ediyorum . BIT"sayısal" da.

* Disclaimer: I work for SQL Sentry.

SQL’in, örneğin DECIMAL (18,2) ve DECIMAL’e (18,0) “farklı türler” olarak davrandığını biliyorum; Bu DECIMAL (18,2) ve NUMERIC (18,2) için de aynı anlama mı geliyor? Birini diğerine atamak teknik olarak bir "dönüşüm" mü?
KutuluMike

@MichaelEdenfield Yeni sorunuz için cevabımı güncelledim.
Aaron Bertrand

1
Bunun eski bir cevap olduğunu biliyorum, ancak yalnızca sayısal ve ondalık sayıların SQL Server'ın hata yapmasına neden olan eş anlamlılar olduğunu düşündüğüm bir durum buldum . Bir başkasının bundan faydalanması ihtimaline karşı bir yorum bırakmam gerektiğini düşündüm.
Zohar Pel

@AaronBertrand Cevabınız için oy kullandım çünkü yardımcı oldu. Her iki tip de aynı görünüyor, öyleyse neden farklı isimlendiriliyorlar? Herhangi bir tarihsel sebep var mı?
Ivanzinho

@ Ivanzinho Sorunuzun retorik olup olmadığından emin değilim, bir sürü teori var (hem bu sayfada hem de bağladığınız cevapta), ancak kesin bir cevap istiyorsanız, muhtemelen şansınızı kaybedeceksiniz. Her iki türü de ilk olarak SQL Server'da uygulayan orijinal mühendisleri bulmanız ve o uygulamanın hafızasına ve o zamanki standardın yorumlanmasına güvenmeniz gerekir.
Aaron Bertrand

15

Ancak pratikte aynıdırlar (SQL 2003 standardından):

21) NUMERIC, precisionve scale.

22) DECIMAL, veri tipini tam olarak belirtir scale; uygulamada tanımlanan ondalık ölçeği ve belirtilen değere eşit veya ondan daha büyük olan uygulama tarafından tanımlanmış ondalık kesinliği belirtir precision.


5
O zamanki temel soru (ve cevabın hayır olduğuna inanıyorum), SQL Server DECIMAL'in hassasiyetini NUMERIC'inkilerden farklı bir şekilde uyguladı mı? Ne standart diyor olabilir yapılabilir gerçekte yapıldı çok daha az önemlidir.
Aaron Bertrand

5
Teşekkürler. Bu, niçin aynı isimde, farklı isimlerle iki tip olduğuna dair takip sorusuna mükemmel bir cevap.
Gabe
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.