Kiểu dữ liệu tốt nhất để lưu trữ giá trị tiền trong MySQL


279

Tôi muốn lưu trữ nhiều bản ghi trong cơ sở dữ liệu MySQL. Tất cả đều chứa giá trị tiền. Nhưng tôi không biết có bao nhiêu chữ số sẽ được chèn cho mỗi cái.
Loại dữ liệu nào tôi phải sử dụng cho mục đích này?
VARCHAR hoặc INT (hoặc các loại dữ liệu số khác)?


13
deimal(10,2)là những gì tôi sử dụng ... bạn có thể điều chỉnh các giá trị tùy thuộc vào kích thước dự kiến
Manse

9
Câu hỏi liên quan là Loại dữ liệu tốt nhất cho tiền tệ ;).
shA.t

Câu trả lời:


370

Vì tiền cần một đại diện chính xác, không sử dụng các loại dữ liệu chỉ gần đúng như thế float. Bạn có thể sử dụng kiểu dữ liệu số điểm cố định cho kiểu đó

decimal(15,2)
  • 15 là độ chính xác (tổng chiều dài của giá trị bao gồm cả số thập phân)
  • 2 là số chữ số sau dấu thập phân

Xem các loại số MySQL :

Các loại này được sử dụng khi điều quan trọng là bảo toàn độ chính xác chính xác, ví dụ với dữ liệu tiền tệ .


3
điều gì có thể là sự khác biệt giữa kiểu dữ liệu thập phân và số cho trường hợp này?
Emilio Gort

60
Trong MySQL decimalnumericđều giống nhau.
juergen d

21
Cá nhân tôi sử dụng numeric(19,4)cho các hồ sơ tài chính giúp bạn chơi tốt hơn và chấp nhận các yêu cầu mới một cách dễ dàng.
YahyaE

10
Tôi đồng ý với YahyaE, càng nhiều số thập phân thì càng tốt. Có một số loại tiền thường sử dụng 3 chữ số thập phân, chẳng hạn như Dinar Bahrain, Jordan hoặc Kuwaiti, vì vậy bạn cần ít nhất 3. Bốn hoặc năm là tốt hơn.
Edwin Hoogerbeets

1
@EdwinHoogerbeets Không phải là một kế toán viên ... nhưng đang điều hành một công ty nhỏ ở Anh ... Tôi nhớ đã đọc ở đâu đó cách đây rất lâu rằng các số liệu tiền tệ nên được lưu trữ thành 4 số thập phân ngay cả với £, $, v.v. thực sự sử dụng 2 vị trí thập phân cuối cùng cho các bối cảnh kế toán tối nghĩa nhất định. Wd cần một kế toán để xác nhận / bác bỏ.
mike gặm nhấm

88

Bạn có thể sử dụng DECIMALhoặc NUMERICcả hai đều giống nhau

Các loại DECIMAL và NUMERIC lưu trữ các giá trị dữ liệu số chính xác. Các loại này được sử dụng khi điều quan trọng là bảo toàn độ chính xác chính xác, ví dụ với dữ liệu tiền tệ. Trong MySQL, NUMERIC được triển khai dưới dạng DECIMAL, do đó, các nhận xét sau đây về DECIMAL áp dụng như nhau cho NUMERIC. : MySQL

I E DECIMAL(10,2)

Cài đặt ví dụ

Đọc tốt


3
Có thể gây nhầm lẫn, nhưng ảnh chụp màn hình của bạn không khớp với văn bản câu trả lời của bạn (độ chính xác, tỷ lệ).
Patrick Hofman

Tôi đang sử dụng số thập phân (10,2) cho giá trị tiền của mình, tuy nhiên khi tôi đặt thứ gì đó như 867.000,00 thì nó được lưu là 867. Tôi đang làm gì sai?
mã hóa

32

Tôi thích sử dụng BIGINTvà lưu trữ các giá trị bằng cách nhân với 100 , để nó sẽ trở thành số nguyên.

Ví dụ: để biểu thị giá trị tiền tệ của 93.49, giá trị sẽ được lưu trữ dưới dạng 9349, trong khi hiển thị giá trị chúng ta có thể chia cho 100 và hiển thị. Điều này sẽ chiếm ít không gian lưu trữ.

Thận trọng:
Hầu hết chúng tôi không thực hiện currency * currencyphép nhân, trong trường hợp nếu chúng tôi đang thực hiện thì hãy chia kết quả cho 100 và lưu trữ, để nó trở về độ chính xác phù hợp.


Tôi nhớ đã được một giáo sư nói về khóa học đại học Hệ thống máy tính của tôi. Tôi đã được dạy một cách chính xác nhất là lưu trữ bằng đồng xu (hoặc cent) bằng cách nhân với 100 và lưu dưới dạng Số nguyên và chia cho 100 để hiển thị cho người dùng. Tôi đoán điều này có lợi ích về tính chính xác và hiệu suất của hệ thống cơ sở dữ liệu.
LondonAppDev

11
Lợi thế hơn là DECIMALgì? Bạn tạo ra một nhu cầu dịch đồng xu sang đô la, và khốn khổ nếu bạn quên nó vào một lúc nào đó.

1
Không gian là lợi thế duy nhất, nhưng vâng, chúng ta cần cẩn thận hơn khi sử dụng tính năng này.
Dinesh PR

4
Trong trường hợp không rõ ràng: hãy cảnh giác khi sử dụng phương pháp loại bỏ tỷ lệ nếu bạn lưu trữ tiền bằng xu phân số (ví dụ: $0.005hoặc $0.12345) vì chúng sẽ không giảm thành số nguyên sau khi nhân với 100. Nếu bạn biết độ chính xác của các giá trị thì sẽ xóa lựa chọn tốt nhất là sử dụng DECIMAL. Nhưng nếu bạn không biết độ chính xác (như trong ví dụ của tôi) thì có FLOATphải là phù hợp?
Quinn Comendant

1
Một lợi thế của phương pháp này xuất hiện khi sử dụng một ngôn ngữ như JavaScript sử dụng IEEE-754 để lưu trữ các số dấu phẩy động. Thông số kỹ thuật này không đảm bảo rằng 0,1 + 0,2 === 0,3 là đúng. Lưu trữ tiền tệ dưới dạng số nguyên cho chắc chắn rằng ứng dụng của bạn sẽ không gặp phải loại lỗi đó. Đây có thể không phải là giải pháp tốt nhất mặc dù. Tôi đến trang này trong khi nghiên cứu các giải pháp và tôi chưa hoàn thành.
Gary Ott

27

Nó phụ thuộc vào nhu cầu của bạn.

Sử dụng DECIMAL(10,2)thường là đủ nhưng nếu bạn cần một chút giá trị chính xác hơn, bạn có thể đặt DECIMAL(10,4).

Nếu bạn làm việc với các giá trị lớn thay thế 10bằng 19.


Tôi đang sử dụng số thập phân (10,2) cho giá trị tiền của mình, tuy nhiên khi tôi đặt thứ gì đó như 867.000,00 thì nó được lưu là 867. Tôi đang làm gì sai?
mã hóa

2
@codeinproTHER Sử dụng phân tách miền địa phương / thập phân sai?
David Balažic

15

Nếu ứng dụng của bạn cần xử lý các giá trị tiền lên tới một nghìn tỷ thì điều này sẽ hoạt động: 13,2 Nếu bạn cần tuân thủ GAAP (Nguyên tắc kế toán được chấp nhận chung) thì hãy sử dụng: 13,4

Thông thường, bạn nên tính tổng giá trị tiền của mình ở mức 13,4 trước khi làm tròn sản lượng thành 13,2.


5
Nếu bạn định lấy Bitcoin, bạn sẽ cần 8 vị trí thập phân, mặc dù hầu hết các ví đều chuyển đến mBTC là 3 en.wikipedia.org/wiki/Bitcoin
Christian

Đừng nghĩ câu trả lời này là đúng. opendata.stackexchange.com/a/10348/13983 @ david.ee có nguồn nào cho việc đó không?
Evan Carroll

@EvanCarroll hãy để tôi trả lời cho david.ee. Tôi nghĩ rằng bài viết này có thể là nguồn rietta.com/blog/2012/03/03/best-data-types-for-currencymoney-in
naXa

@naXa liên kết không trích dẫn bất cứ điều gì từ bất kỳ nguồn nào hỗ trợ cho yêu cầu sử dụng 13,4 cho GAAP. Tất cả những gì bạn đã làm là liên kết đến một bài viết đưa ra tuyên bố không có căn cứ tương tự.
iheanyi

6

Quả thực điều này phụ thuộc vào sở thích của lập trình viên. Cá nhân tôi sử dụng: numeric(15,4)để tuân thủ Nguyên tắc Kế toán được chấp nhận chung ( GAAP ) .


5
Nó không có gì để làm với "sở thích của lập trình viên" hoặc những gì bạn 'sử dụng cá nhân'. Nó được quyết định bởi miền vấn đề, đòi hỏi một cơ số thập phân. Đây không phải là vấn đề mà lập trình viên có thể thực hiện sở thích cá nhân của riêng mình.
Hầu tước Lorne

3

Hãy thử sử dụng

Decimal(19,4)

điều này thường hoạt động với mọi DB khác


3

Chúng tôi sử dụng double.

* thở hổn hển *

Tại sao?

Bởi vì nó có thể đại diện cho bất kỳ số 15 chữ số nào mà không có ràng buộc về vị trí của dấu thập phân . Tất cả chỉ vì 8 byte!

Vì vậy, nó có thể đại diện:

  • 0.123456789012345
  • 123456789012345.0

... Và bất cứ điều gì ở giữa.

Điều này rất hữu ích vì chúng tôi đang giao dịch với các loại tiền tệ toàn cầudoublecó thể lưu trữ nhiều số thập phân khác nhau mà chúng tôi có thể gặp phải.

Một doubletrường duy nhất có thể đại diện cho 999.999.999.999.999 bằng đồng Nhật Bản, 9,999.999.999.999,99,99 đô la Mỹ và thậm chí 9,999.999.999999999 bằng bitcoin

Nếu bạn thử làm tương tự với decimal, bạn cần decimal(30, 15)chi phí 14 byte.

Hãy cẩn thận

Tất nhiên, sử dụng doublekhông phải không có sự cẩn thận.

Tuy nhiên, nó không mất độ chính xác như một số xu hướng chỉ ra. Mặc dù doublebản thân nó có thể không chính xác trong hệ thống cơ sở 10 , chúng ta có thể làm cho nó chính xác bằng cách làm tròn giá trị chúng ta kéo từ cơ sở dữ liệu đến các vị trí thập phân quan trọng của nó. Nếu cần đó là. (ví dụ: Nếu nó sẽ được xuất ra, và cần có đại diện cơ sở 10.)

Hãy cẩn thận, bất cứ khi nào chúng tôi thực hiện số học với nó, chúng tôi cần bình thường hóa kết quả (bằng cách làm tròn nó đến các vị trí thập phân quan trọng của nó) trước:

  1. Thực hiện so sánh trên đó.
  2. Viết lại cho cơ sở dữ liệu.

Một loại cảnh báo khác là, không giống như decimal(m, d)nơi cơ sở dữ liệu sẽ ngăn các chương trình chèn một số có nhiều hơn mchữ số, không có xác nhận nào như vậy tồn tại double. Một chương trình có thể chèn một người dùng nhập giá trị 20 chữ số và cuối cùng nó sẽ được ghi âm một cách không chính xác.


Lần đầu tiên tôi thấy một câu trả lời như thế này, thật thú vị. H: Nếu tôi viết một số float như 1.41 vào cơ sở dữ liệu và vì một số lý do, tôi cần nhân nó với một số lượng lớn trong mysql, như 1.000.000.000.000. Kết quả làm tròn chính xác sẽ là: 1.410.000.000.000?
roelleor

@roelleor Để kết quả chính xác là 1.410.000.000.000 (dấu phẩy là dấu phân cách hàng nghìn), đầu vào được giả sử là 1.410000000000(mười hai chữ số thập phân có ý nghĩa), nhưng nhân với 1.000.000.000.000 (là 13 chữ số có nghĩa của dấu thập phân) có nghĩa là chúng tôi đang làm việc tại ít nhất 25 chữ số kết hợp có ý nghĩa. Điều này vượt xa 15 có sẵn cho một đôi, vì vậy thiết kế khôn ngoan tôi nghĩ rằng nó sẽ rất bị phá vỡ.
antak

2

Tại thời điểm câu hỏi này được hỏi không ai nghĩ về giá Bitcoin. Trong trường hợp BTC, có lẽ không đủ để sử dụng DECIMAL(15,2). Nếu Bitcoin sẽ tăng lên 100.000 đô la trở lên, chúng tôi sẽ cần ít nhất là DECIMAL(18,9)để hỗ trợ tiền điện tử trong các ứng dụng của chúng tôi.

DECIMAL(18,9)mất 12 byte không gian trong MySQL ( 4 byte cho mỗi 9 chữ số ).


> Một bitcoin có thể được chia thành 8 chữ số thập phân. Do đó, 0,00000001 BTC là số tiền nhỏ nhất có thể được xử lý trong giao dịch. Tôi nghĩ bạn có nghĩa là 8 thay vì 9?
nguy hiểm89

1
Tôi biết, nhưng 9 có cùng dung lượng đĩa là 8. Từ tài liệu MySQL: "Các giá trị cho các cột DECIMAL được lưu trữ bằng định dạng nhị phân gói chín chữ số thập phân thành 4 byte"
bizwiz

Ow xin lỗi, bây giờ tôi có được bạn. Cảm ơn.
nguy hiểm89

2

Lưu trữ tiền khi BIGINTnhân với 100 hoặc nhiều hơn với lý do sử dụng ít dung lượng lưu trữ hơn sẽ không có ý nghĩa trong tất cả các tình huống "bình thường".

  • Để phù hợp với GAAP, việc lưu trữ tiền tệ trong DECIMAL(13,4)
  • Hướng dẫn sử dụng MySQL đọc rằng nó cần 4 byte cho mỗi 9 chữ số để lưu trữ DECIMAL.
  • DECIMAL(13,4) đại diện cho 9 chữ số + 4 chữ số phân số (vị trí thập phân) => 4 + 2 byte = 6 byte
  • so sánh với 8 byte cần thiết để lưu trữ BIGINT.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.