Apakah ada perbedaan sama sekali antara NUMERIC dan DECIMAL?


47

Saya tahu bahwa tipe data NUMERIC dan DECIMAL di SQL Server berfungsi sama: sintaks untuk membuatnya adalah sama, rentang nilai yang dapat Anda simpan di dalamnya sama, dll.

Namun, dokumentasi MSDN menjelaskan hubungan antara keduanya karena ini:

numerik secara fungsional setara dengan desimal.

Biasanya, ketika saya melihat kualifikasi " setara secara fungsional ", itu berarti bahwa dua hal tidak persis sama, tetapi mereka adalah dua jenis berbeda yang tidak dapat dibedakan dari luar .

Apakah implikasi ini benar? Apakah ada perbedaan antara NUMERIC dan DECIMAL yang kebetulan berperilaku sama dengan pengamat luar? Atau apakah mereka sebenarnya setara, misalnya apakah NUMERIC hanya sinonim warisan untuk DECIMAL?


1
Anda mungkin menemukan perbedaan dalam dukungan di luar SQL Server, misalnya saya baru saja menyadari perbedaan aneh dalam SSIS .
Aaron Bertrand

Jawaban:


56

Mereka sebenarnya setara, tetapi mereka adalah tipe independen, dan bukan sinonim secara teknis , seperti ROWVERSIONdan TIMESTAMP- meskipun mereka mungkin telah disebut sebagai sinonim dalam dokumentasi pada satu waktu . Itu adalah arti sinonim yang sedikit berbeda (misalnya mereka tidak dapat dibedakan kecuali dalam nama, tidak satu alias alias untuk yang lain). Ironis kan?

Apa yang saya tafsirkan dari kata-kata dalam MSDN sebenarnya:

Jenis-jenis ini identik, mereka hanya memiliki nama yang berbeda.

Selain type_idnilainya, semuanya di sini identik:

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

Saya sama sekali tidak memiliki pengetahuan tentang perbedaan perilaku antara keduanya, dan kembali ke SQL Server 6.5, selalu memperlakukan mereka sebagai 100% dipertukarkan.

untuk DECIMAL (18,2) dan NUMERIC (18,2)? Menugaskan satu ke yang lain secara teknis merupakan "konversi"?

Hanya jika Anda melakukannya secara eksplisit. Anda dapat membuktikan ini dengan mudah dengan membuat tabel dan kemudian memeriksa rencana kueri untuk kueri yang melakukan eksplisit atau - Anda mungkin mengharapkan - konversi tersirat. Ini tabel sederhana:

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

Sekarang jalankan pertanyaan ini dan tangkap rencana:

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

Seperti yang ditunjukkan dalam SQL Sentry Plan Explorer *, paket tersebut tidak terlalu menarik:

masukkan deskripsi gambar di sini

Tetapi tab Ekspresi yakin adalah:

masukkan deskripsi gambar di sini

Seperti yang saya komentari di atas, kami memiliki konversi eksplisit tempat kami memintanya, tetapi tidak ada konversi eksplisit di mana kami mungkin mengharapkannya. Tampaknya pengoptimal memperlakukan mereka juga dapat dipertukarkan.

Silakan dan coba tes ini juga (data dan indeks).

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

Sekarang jalankan query ini:

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 tidak memiliki konversi (sebenarnya tab Ekspresi kosong):

masukkan deskripsi gambar di sini

Bahkan ini tidak mengarah pada konversi yang tidak terduga. Tentu saja Anda melihatnya di RHS dalam predikat, tetapi dalam kasus apa pun konversi tidak boleh terjadi terhadap data kolom untuk memfasilitasi pencarian (apalagi memaksa pemindaian).

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

Secara pribadi, saya lebih suka menggunakan istilah ini DECIMALhanya karena jauh lebih akurat dan deskriptif. BITjuga "numerik".

* Disclaimer: I work for SQL Sentry.

Saya tahu bahwa SQL memperlakukan, misalnya DECIMAL (18,2) dan DECIMAL (18,0) sebagai "tipe yang berbeda"; apakah ini berarti hal yang sama berlaku untuk DECIMAL (18,2) dan NUMERIC (18,2)? Menugaskan satu ke yang lain secara teknis merupakan "konversi"?
KutuluMike

@MichaelEdenfield Memperbarui jawaban saya untuk pertanyaan baru Anda.
Aaron Bertrand

1
Saya tahu ini adalah jawaban lama tapi saya baru saja menemukan sebuah kasus di mana berpikir bahwa angka dan desimal adalah sinonim yang menyebabkan SQL Server menimbulkan kesalahan. Hanya berpikir saya harus meninggalkan komentar di sini kalau-kalau ada orang lain yang mendapat manfaat dari itu.
Zohar Peled

@ AaronBertrand Saya memberikan suara untuk jawaban Anda karena sangat membantu. Kedua jenis terlihat identik jadi jika itu yang terjadi, mengapa mereka dinamai berbeda? adakah alasan historis ?
Ivanzinho

@ Ivanzinho Saya tidak yakin apakah pertanyaan Anda retoris, ada banyak teori (baik di halaman ini dan jawaban yang Anda tautkan), tetapi jika Anda menginginkan jawaban yang pasti, Anda mungkin akan kurang beruntung. Anda harus melacak insinyur asli yang pertama kali mengimplementasikan kedua jenis dalam SQL Server, dan mengandalkan memori mereka dari implementasi itu dan interpretasi mereka terhadap standar pada waktu itu.
Aaron Bertrand

15

Mereka identik dalam praktiknya, namun (dari standar SQL 2003):

21) NUMERIC menentukan tipe data numerik yang tepat, dengan presisi desimal dan skala yang ditentukan oleh precisiondan scale.

22) DECIMAL menentukan tipe data numerik yang tepat, dengan skala desimal yang ditentukan oleh scaledan presisi desimal yang ditentukan implementasi sama dengan atau lebih besar dari nilai yang ditentukan precision.


5
Pertanyaan mendasar kemudian (dan saya percaya jawabannya tidak), apakah SQL Server mengimplementasikan ketepatan DECIMAL berbeda dari NUMERIC. Apa yang dikatakan standar dapat dilakukan adalah jauh kurang relevan daripada apa yang sebenarnya dilakukan.
Aaron Bertrand

5
Terima kasih. Ini adalah jawaban yang bagus untuk pertanyaan lanjutan mengapa ada dua tipe dengan nama yang berbeda tetapi perilaku yang identik.
Gabe
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.