มีความแตกต่างระหว่าง NUMERIC และ DECIMAL หรือไม่?


47

ฉันรู้ว่าชนิดข้อมูล NUMERIC และ DECIMAL ใน SQL Server ทำงานเหมือนกัน: ไวยากรณ์สำหรับการสร้างนั้นเหมือนกันช่วงของค่าที่คุณสามารถจัดเก็บได้นั้นเหมือนกัน ฯลฯ

อย่างไรก็ตามเอกสาร MSDN อธิบายถึงความสัมพันธ์ระหว่างสองสิ่งนี้:

ตัวเลขมีฟังก์ชันเทียบเท่ากับทศนิยม

โดยปกติเมื่อฉันเห็นรอบคัดเลือก " หน้าที่เทียบเท่า" ก็หมายความว่าทั้งสองสิ่งที่ไม่ตรงเหมือนกัน แต่ที่พวกเขาเป็นสองประเภทต่าง ๆ ที่มีความแตกต่างจากด้านนอก

ความหมายนี้เป็นจริงหรือไม่? มีความแตกต่างระหว่าง NUMERIC และ DECIMAL ที่เพิ่งเกิดขึ้นกับผู้สังเกตการณ์ภายนอกหรือไม่ หรือว่าเทียบเท่ากันจริง ๆเช่น NUMERIC เป็นเพียงคำพ้องความหมายดั้งเดิมสำหรับ DECIMAL หรือไม่


1
คุณอาจจะพบความแตกต่างในการสนับสนุนด้านนอกของ SQL Server ตัวอย่างเช่นผมได้ทำเพียงตระหนักถึงความแตกต่างแปลกใน SSIS
Aaron Bertrand

คำตอบ:


56

พวกมันเทียบเท่ากันจริง แต่เป็นประเภทอิสระและไม่ใช่คำพ้องความหมายทางเทคนิคเช่นROWVERSIONและTIMESTAMP- แม้ว่าพวกเขาอาจถูกเรียกว่าคำพ้องความหมายในเอกสารประกอบในครั้งเดียว นั่นคือความหมายที่แตกต่างกันเล็กน้อยของคำพ้องความหมาย (เช่นพวกเขาจะแยกไม่ออกยกเว้นในชื่อไม่มีใครเป็นนามแฝงสำหรับคนอื่น ๆ ) แดกดันใช่มั้ย

สิ่งที่ฉันตีความจากถ้อยคำใน MSDN เป็นจริง:

ประเภทเหล่านี้เหมือนกันพวกเขามีชื่อต่างกัน

นอกเหนือจากtype_idค่าทุกอย่างที่นี่เหมือนกัน:

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

ฉันไม่มีความรู้เกี่ยวกับพฤติกรรมที่แตกต่างระหว่างสองอย่างนี้อย่างแน่นอนและกลับไปที่ SQL Server 6.5 ได้ถือว่าพวกเขาสามารถใช้แทนกันได้ 100%

สำหรับ DECIMAL (18,2) และ NUMERIC (18,2)? การกำหนดให้กับอีกอันหนึ่งเป็นเทคนิค "การแปลง" หรือไม่?

เฉพาะในกรณีที่คุณทำอย่างชัดเจน คุณสามารถพิสูจน์สิ่งนี้ได้อย่างง่ายดายโดยการสร้างตารางจากนั้นตรวจสอบแผนแบบสอบถามสำหรับคิวรีที่ดำเนินการอย่างชัดเจนหรือ - คุณอาจคาดหวัง - การแปลงโดยนัย นี่เป็นตารางง่าย ๆ :

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

ตอนนี้เรียกใช้แบบสอบถามเหล่านี้และจับแผน:

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 * แผนไม่น่าสนใจจริงๆ:

ป้อนคำอธิบายรูปภาพที่นี่

แต่แท็บนิพจน์แน่ใจว่าเป็น:

ป้อนคำอธิบายรูปภาพที่นี่

ตามที่ฉันแสดงความคิดเห็นไว้ด้านบนเรามีการแปลงที่ชัดเจนซึ่งเราขอให้พวกเขา แต่ไม่มีการแปลงที่ชัดเจนที่เราอาจคาดหวังไว้ ดูเหมือนว่าเครื่องมือเพิ่มประสิทธิภาพจะถือว่าพวกเขาเป็นที่ใช้แทนกันได้เช่นกัน

ไปข้างหน้าและลองทดสอบนี้ด้วย (ข้อมูลและดัชนี)

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

ตอนนี้เรียกใช้แบบสอบถามนี้:

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;

แผนไม่มีการแปลง (อันที่จริงแล้วแท็บนิพจน์นั้นว่างเปล่า):

ป้อนคำอธิบายรูปภาพที่นี่

แม้สิ่งเหล่านี้จะไม่นำไปสู่การแปลงที่ไม่คาดคิด แน่นอนคุณเห็นมันใน RHS ในภาคแสดง แต่ไม่มีการแปลงใด ๆ เกิดขึ้นกับข้อมูลคอลัมน์เพื่ออำนวยความสะดวกในการค้นหา (บังคับน้อยกว่าการสแกน)

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

โดยส่วนตัวแล้วฉันชอบที่จะใช้คำDECIMALเพียงเพราะมันแม่นยำและเป็นคำอธิบายมากขึ้น BITก็คือ "ตัวเลข" ด้วย

* Disclaimer: I work for SQL Sentry.

ฉันรู้ว่า SQL ปฏิบัติเช่น DECIMAL (18,2) และ DECIMAL (18,0) ว่าเป็น "different types"; สิ่งนี้หมายความว่าเหมือนกันกับ DECIMAL (18,2) และ NUMERIC (18,2) หรือไม่ การกำหนดให้กับอีกอันหนึ่งเป็นเทคนิค "การแปลง" หรือไม่?
KutuluMike

@MichaelEdenfield อัปเดตคำตอบสำหรับคำถามใหม่ของคุณ
Aaron Bertrand

1
ฉันรู้ว่านี่เป็นคำตอบเก่า แต่ฉันเพิ่งพบกรณีที่คิดว่าตัวเลขและทศนิยมเป็นคำพ้องความหมายทำให้ SQL Server เกิดข้อผิดพลาด แค่คิดว่าฉันควรแสดงความคิดเห็นที่นี่ในกรณีที่คนอื่นอาจได้รับประโยชน์จากมัน
Zohar Peled

@AaronBertrand ฉันโหวตให้คำตอบของคุณเพราะมันมีประโยชน์ ทั้งสองประเภทดูเหมือนจะเหมือนกันดังนั้นถ้าเป็นเช่นนั้นทำไมพวกเขาถึงตั้งชื่อต่างกัน? มีเหตุผลทางประวัติศาสตร์หรือไม่?
Ivanzinho

@Ivanzinho ฉันไม่แน่ใจว่าคำถามของคุณเป็นโวหารมีหลายทฤษฎี (ทั้งในหน้านี้และคำตอบที่คุณเชื่อมโยง) แต่ถ้าคุณต้องการคำตอบที่ชัดเจนคุณอาจจะโชคไม่ดี คุณต้องติดตามวิศวกรดั้งเดิมที่ใช้ทั้งสองประเภทใน SQL Server เป็นครั้งแรกและพึ่งพาหน่วยความจำของทั้งการใช้งานนั้นและการตีความมาตรฐานในขณะนั้น
Aaron Bertrand

15

อย่างไรก็ตามมันเหมือนกันในทางปฏิบัติ (จากมาตรฐาน SQL 2003):

21) ตัวเลขระบุชนิดข้อมูลที่เป็นตัวเลขที่แน่นอนด้วยความแม่นยำทศนิยมและขนาดตามที่ระบุไว้ และprecisionscale

22) ทศนิยมระบุชนิดข้อมูลที่เป็นตัวเลขที่แน่นอนที่มีขนาดทศนิยมที่ระบุโดยscaleและ การดำเนินงานที่กำหนดไว้precisionแม่นยำทศนิยมเท่ากับหรือมากกว่าค่าของที่ระบุ


5
คำถามพื้นฐานแล้ว (และฉันเชื่อว่าคำตอบคือไม่), SQL Server ใช้ความแม่นยำของ DECIMAL แตกต่างจาก NUMERIC หรือไม่ สิ่งที่มาตรฐานบอกว่าสามารถทำได้นั้นมีความเกี่ยวข้องน้อยกว่าสิ่งที่ทำจริง
Aaron Bertrand

5
ขอบคุณ นี่เป็นคำตอบที่ดีสำหรับคำถามติดตามว่าทำไมมีสองประเภทที่มีชื่อแตกต่างกัน แต่มีพฤติกรรมที่เหมือนกัน
Gabe
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.