# Athena Engine Version2でDecimalにCastした値の挙動を確認してみた

Athenaで小数点以下の桁数を維持しつつ集計を試みたものの、DECIMALが想定外の動作をしていたため、意図した構成にてデータを扱う手段を模索してみました。
2021.10.06

Athenaで小数点以下の計算で精度を保たせる場合、手段の一つとしてDecimalへの型キャストを用いることがあります。例えば、`DECIMAL(11,5)、DECIMAL(20, 15)` 等。ただ、Decimalで出力したもののDoubleと同等の値になってしまい、意図した結果と大幅に異なることがあります。

## 型変換と結果の値

``````SELECT
'0.2912000000' as original,
typeof('0.2912000000') as "varchar",
typeof(cast('0.2912000000' as DOUBLE)) as "double",
typeof(cast('0.2912000000' as REAL)) as "real",
typeof(cast('0.2912000000' as DECIMAL(20,10))) as "decimal",
cast('0.2912000000' as DOUBLE) as "varchar_to_double",
cast('0.2912000000' as REAL) as "varchar_to_real",
cast('0.2912000000' as DECIMAL(20,10)) as "varchar_to_decimal";``````

## 型変換が正常に行われているのか確認する

DECIMALへの型変換にて異常が発生しているのかも、という疑問を再度VARCHARに変換することで解消してみます。

``````SELECT
'0.2912000000' as original,
cast(cast('0.2912000000' as DOUBLE) as VARCHAR) as "varchar_to_double_tovarchar",
cast(cast('0.2912000000' as REAL) as VARCHAR) as "varchar_to_real_to_varchar",
cast(cast('0.2912000000' as DECIMAL(20,10)) as VARCHAR) as "varchar_to_decimal_to_varchar";``````

Presto 0.198以降明示的な型指定子のない10進リテラル(1.2など)はDECIMALとして扱われるとあります。しかし、Athenaのエンジンバージョン2はPresto 0.217ベースながらもDECIMALとして値が出力されていません。

For compatibility reasons decimal literals without explicit type specifier (e.g. 1.2) are treated as values of the DOUBLE type by default up to version 0.198. After 0.198 they are parsed as DECIMAL.

Athena エンジンバージョン 2 は Presto 0.217 に基づいています。

## 計算してみる

``````SELECT
cast('0.2912000000' as DOUBLE) + cast('0.2912000000' as DOUBLE) as "varchar_to_double_calc",
cast('0.2912000000' as REAL) + cast('0.2912000000' as REAL) as "varchar_to_real_calc",
cast('0.2912000000' as DECIMAL(20,10)) + cast('0.2912000000' as DECIMAL(20,10)) as "varchar_to_decimal_calc";``````

``````SELECT
cast(cast('0.2912000000' as DOUBLE) + cast('0.2912000000' as DOUBLE) as VARCHAR) as "varchar_to_double_calc_to_varchar",
cast(cast('0.2912000000' as REAL) + cast('0.2912000000' as REAL) as VARCHAR) as "varchar_to_real_calc_to_varchar",
cast(cast('0.2912000000' as DECIMAL(20,10)) + cast('0.2912000000' as DECIMAL(20,10)) as VARCHAR) as "varchar_to_decimal_calc_to_varchar";``````

DOUBLEとREALで小数点以下末尾0を除いて維持できつつ、DECIMALでは小数点以下の桁数も維持されました。

## あとがき

Athenaで型をDECIMALにして扱う場合、小数点以下の精度が異なり、結果 `SUM` 等実行後に大幅なズレが生じることもあります。今後のPrestoエンジンのバージョンアップにて変わる可能性もありますが、精度を求める場合には今回のように結果をVARCHAR型で維持する等の選択肢も検討してみましょう。