PostgreSQL : 통화에 어떤 데이터 유형을 사용해야합니까?


128

여기에Money 설명 된대로 유형이 권장되지 않는 것 같습니다.

내 애플리케이션은 통화를 저장해야합니다. 어떤 데이터 유형을 사용해야합니까? 숫자, 돈 또는 FLOAT?


7
전체 스레드를 읽었다면 Numeric이 갈 길입니다.
razpeitia 2013 년

여러 통화로 작업하고 금액 외에 통화 코드를 저장하는 데 관심이있는 사람 은 데이터베이스 (SO) 및 ISO 4217 (Wikipedia) 에서 통화 모델링 을 볼 수 있습니다 . 짧은 대답은 두 개의 열이 필요하다는 것입니다.
Fabien Snauwaert 2019

답변:


90

강제 2 단위 정밀도의 숫자 입니다. 통화를 나타 내기 위해 float 또는 float와 같은 데이터 유형을 사용하지 마십시오. 그렇게한다면 재무 보고서의 수익 수치가 + 또는-몇 달러에 의해 부정확 할 때 사람들이 불만을 갖게 될 것입니다.

화폐 유형은 내가 말할 수있는 한 역사적인 이유로 남아 있습니다.


9
그것이 부동 소수점을 피하는 이유가 아닙니다. 어떤 정밀도를 사용하든 10의 거듭 제곱으로 나누지 않는 것으로 나누면 숫자도 반올림 오류가 발생합니다. (2 정밀 나쁜 생각 어쨌든 ... 워드 프로세서를 확인할 수 있습니다.)
Doradus

6
임의의 통화를 지원하려면 스케일을 2와 같게 만들지 마십시오 (postgresql 용어에서 정밀도는 모든 자릿수입니다. 예를 들어 121.121에서는 6과 같습니다). 1000 개의 하위 단위가 하나의 단위와 동일한 바레인 디나르와 같은 통화가 있고 하위 단위가 전혀없는 통화가 있습니다.
Nikolay Arhipov

@NikolayArhipov 좋은 지적, 그래서 최대는 실제로scale - precision
Konrad

1
numeric(3,2)최대 저장할 수있을 것입니다9.99 3-2 = 1
콘라드

5
이러지마! 값을 다른 언어로로드하기 전에 100을 곱한 다음 정수로 수학을 수행 할 계획이 아니라면 잘못된 결과를 얻게됩니다. 물건을 센트 (가장 작은 통화 단위)로 저장하고 번거 로움을 덜어줍니다. 많은 경우 매우 나쁜 대답입니다.
Avamander

111

귀하의 출처는 공식적인 것이 아닙니다. 그것은 2011 년으로 거슬러 올라갑니다. 그리고 저는 저자도 알아볼 수 없습니다. 돈 유형이 공식적으로 "실망"경우 PostgreSQL은 매뉴얼에 그렇게 말 것 - 그것이하지 않는 .

들어 더 공식 소스 읽기 (그냥이 주에서!)를 pgsql-일반적으로이 스레드를 , 다르시 JM 가인 (돈 유형의 원래 저자)와 톰 레인을 포함한 핵심 개발자 진술과 :

최근 릴리스의 개선 사항에 대한 관련 답변 (및 의견!) :

기본적으로 money(매우 제한적인) 용도가 있습니다. 포스트 그레스 위키는 크게, 그것을 피할 그 좁게 정의 된 경우를 제외하기 위해 제안합니다. 장점 numeric성능 입니다.

decimalnumericPostgres 의 별칭이며 화폐 데이터에 널리 사용되며 "임의의 정밀도"유형입니다. 설명서 :

이 유형 numeric은 매우 많은 자릿수의 숫자를 저장할 수 있습니다. 특히 정확성이 필요한 금액 및 기타 수량을 저장하는 데 권장됩니다.

개인적으로 integer분수 센트가 발생하지 않는 경우 (기본적으로 돈이 합리적 일 경우) 센트 를 나타내는 통화로 저장하는 것을 좋아합니다 . 언급 된 다른 옵션보다 더 효율적입니다.


4
돈 유형이 적어도 권장되지 않는다는 인상을주는 메일 링리스트에 대한 몇 가지 토론이 있습니다. 예 : 여기 : postgresql.nabble.com/Money-type-todos-td1964190.html#a1964192 plus to be fair : the 버전 8.2 수동 않은 호출은 더 이상 사용되지 : postgresql.org/docs/8.2/static/datatype-money.html
a_horse_with_no_name

11
@a_horse_with_no_name : 귀하의 링크는 2007 년의 스레드에 대한 것입니다. 이는 8.2가 현재 버전이고 money실제로 유형이 더 이상 사용되지 않는 시기이기도 합니다. 문제가 수정되었으며 유형이 이후 버전에서 다시 추가되었습니다. 개인적으로 저는 integer센트 를 나타내는 통화를 저장하는 것을 좋아합니다 .
Erwin Brandstetter

1
어윈, 당신은 데이터베이스 관점에서만 옳은 생각 일 수 있습니다. 그러나 Postgresql + Java를 결합하면 (내 경험상) 전혀 좋지 않습니다. 귀하의 의견을 읽으면서 대부분의 통화 필드에 MONEY를 사용했으며 이제 Java 예외 가 발생했습니다. " SQLException 발생 : org.postgresql.util.PSQLException : Bad value for type double : 2,500.00 ". 나는 봤는데 좋은 해결책을 찾지 못했기 때문에 지금은 모두 NUMERIC 또는 DECIMAL로 변경하는 지루한 작업에 빠져 있습니다!
MD

1
@MD : 유감입니다.하지만 저는 분명히 Java에 대해 말하지 않았습니다. 오류 메시지가 이상합니다. "더블"? 천 단위 구분자도 문제가 될 수 있습니다. 그것에 대해 새로운 질문을 시작하는 것이 좋습니다.
Erwin Brandstetter 2015 년

2
@PirateApp : 네, 개인적으로 좋아합니다. 내 대답의 마지막 문장을 놓쳤을 수도 있습니다.
Erwin Brandstetter 2018 년

68

선택 사항은 다음과 같습니다.

  1. bigint: 금액을 센트로 저장합니다. 이것이 EFTPOS 트랜잭션이 사용하는 것입니다.
  2. decimal(12,2): 소수점 이하 두 자리로 금액을 저장합니다. 이것은 대부분의 일반 원장 소프트웨어가 사용하는 것입니다.
  3. float: 끔찍한 아이디어-부적절한 정확성. 이것은 순진한 개발자가 사용하는 것입니다.

옵션 2는 가장 일반적이며 작업하기 가장 쉽습니다. 정밀도 (내 예에서는 12, 모두 12 자리 숫자)를 사용자에게 가장 적합한만큼 크거나 작게 만드십시오.

계산 (예 : 환율 포함)의 결과 인 여러 트랜잭션을 비즈니스 의미가있는 단일 값으로 집계하는 경우 정확한 매크로 값을 제공하려면 정밀도가 더 높아야합니다. decimal(18, 8)합계가 정확하고 표시를 위해 개별 값을 센트 정밀도로 반올림 할 수 있도록 다음과 같은 것을 사용하는 것이 좋습니다.


10
어떤 종류의 역세 계산이나 외환으로 작업하는 경우 소수점 이하 4 자리 이상이 필요합니다. 그렇지 않으면 데이터가 손실됩니다. 그래서 numeric(15,4)또는 numeric(15,6)좋은 생각입니다.
Petrus Theron

3
네 번째 옵션이 있습니다. 즉, 문자열을 사용하고 호스트 언어에서 동등한 비 손실 십진수 유형을 사용하는 것입니다.
ioquatix

2
스케일링 된 정수는 어떻습니까? 1000x 스케일링 계수로 10000045로 저장하면 10000.045를 저장하면 손상되지 않을까요?
PirateApp

26

모든 통화 필드를 다음과 같이 유지합니다.

numeric(15,6)

소수 자리를 많이 사용하는 것은 과도 해 보이지만 여러 통화를 처리해야 할 가능성이 아주 적다면 변환을 위해 그 정도의 정밀도가 필요합니다. 사용자에게 무엇을 제시하든 항상 미국 달러로 저장합니다. 그런 식으로 나는 관련된 날의 환율을 고려할 때 다른 통화로 쉽게 변환 할 수 있습니다.

하나의 통화 외에는 아무것도하지 않는다면, 여기서 최악의 것은 0을 저장하기 위해 약간의 공간을 낭비한 것입니다.


6
잘림이 없기 때문에 결과가 잘못 될 위험이 있습니다. 0이 아닌 값이 의도하지 않게 나머지 소수점 자리 (예 : 0.333333 달러가 포함 된 가격 필드)로 유출되는 경우 시스템이 각 항목 3 개를 각각 $ 0.33에 구매하여 $ 0.99 대신 최대 $ 1.00까지 구매 한 결과를 표시 할 수 있습니다.
Peteris

1
Perteris, 대신 무엇을 제안합니까? 이 반올림에 얼마나 많은 정밀도를 던지더라도 문제가 될 수 있습니다. 이것이 이상적이지 않더라도 더 나은 방법을 찾지 못했습니다.
Michael Collette 2016

3
포인트를 고정하고 적절한 곳에서 자릅니다. 고객에게 제공되는 가격과 같이 "저장 가능한"화폐 가치에 도달하자마자 적절한 메트릭에 있어야하며 대부분의 경우 표준 소매 환경에서 전체 센트가됩니다. 비즈니스 요구 사항이 다른 경우 (예 : 단위당 대량 상품의 가격) 정확도 설정이 다를 수 있지만 저장과 함께 표시 를 처리해야합니다 . 화폐 번호를 소수점 x 자리로 표시하는 경우 (또는 그 반대로, 예를 들어 수천 개로) 그런 다음 정확도로 저장해야합니다 .
Peteris

작동 할 수있는 많은 소매 관련 사이트의 경우. 내가 함께 일하는 주요 프로젝트는 한 쪽이 동일한 비용을 한 통화로, 클라이언트는 다른 통화로, 아직 제 3의 공급자에 대해 볼 필요가있을 수 있습니다.
Michael Collette 2016

19

다음으로 저장된 64 비트 정수 사용 bigint

마이크로 달러 (또는 유사한 주요 통화)를 사용하는 것이 좋습니다. 마이크로는 백만 분의 1을 의미하므로 1 마이크로 달러 = $ 0.000001입니다.

  • 사용하기 쉽고 모든 언어와 호환됩니다.
  • 센트의 일부를 처리하기에 충분한 정밀도.
  • 매우 작은 단위당 가격 책정 (예 : 광고 노출 또는 API 요금)에 적용됩니다.
  • 저장을위한 데이터 크기가 문자열 또는 숫자보다 작습니다.
  • 계산을 통해 정확도를 유지하고 최종 출력에 반올림을 적용하기 쉽습니다.

1
이것은 가장 정답이며 합리적인 소프트웨어는 가장 작은 통화 단위를 처리합니다. 정수에 대한 모든 수학을 수행한다는 것은 언어 별 float 맹 글링을 다룰 필요가 없음을 의미합니다.
Avamander

1
그것도 사용할 것입니다. 감사합니다

왜 이것이 numeric(15,6)다른 대답에서 제안 되었습니까?
Juliusz Gonera

@JuliuszGonera 답변에 나열된 이유. 정수는 더 작고 모든 곳에서 지원되며 모든 수학 잘림 문제를 방지합니다. 기본적으로 숫자를 사용하지만 소수를 이동하여 훨씬 더 호환되는 정수를 갖게됩니다.
Mani Gandham

1
아, 맞다, 보관에 관한 부분을 놓쳤다. 감사! "사용이 간편하고 모든 언어와 호환 가능"과 관련하여 안타깝게도 JavaScript는 최대 9007199254740991의 정수를 지원합니다. 이는 최대 값보다 1000 배 이상 작은 정수입니다 bigint. 이 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... 하지만 (예를 들어, 당신이 곱 그것을 플로트로 쉽게 통화 변환을 수행 할 수 없을 때) (지금은) 제한된 지원이 제공 및주의 사항 . 마이크로 달러를 사용하여 JS 정수에 저장할 수있는 최대 값이 90 억 달러라는 점을 감안할 때 대부분의 경우 여전히 좋습니다.
Juliusz Gonera

3

BigInt통화를 가장 작은 통화 단위로 화폐 가치를 나타내는 양의 정수로 저장하는 데 사용 합니다 (예 : $ 1.00를 저장하려면 100 센트, ​​100 엔을 저장하려면 100 (일본 엔, 0 진수 통화)) 이것은 Stripe가하는 일입니다. 글로벌 전자 상거래를위한 가장 중요한 금융 서비스 회사입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.