はじめに
LambdaとAthenaを使ってデータを取得、返却するプログラムを作りテストをしたところ「0.0003」などの小数が「3.0E-4」などの指数表記で帰ってきていました。
1つのLambdaで指定したテーブルの全列を取得できるような仕様にしており、特定の列をCASTするといったアプローチは取れなかったため指定されたテーブルのスキーマーをもとに取得列を動的に作成するLambdaを作成しました。
本題
main.py
import json
import awswrangler as wr
DATABASE = 'database_name'
TABLE_NAME = 'table_name'
OUTPUT_LOCATION='s3://example'
def lambda_handler(event, context):
try:
# テーブルの列名、型を取得
query = f"""
select
*
from information_schema.columns
where LOWER(table_name) = LOWER('{TABLE_NAME}')
;
"""
df = wr.athena.read_sql_query(sql=query, database=DATABASE, s3_output=OUTPUT_LOCATION)
# 型がdoubleの時はdecimalにcastする(decimalにすると指数表記じゃなくなる)
str_columns = ""
for index, row in df.iterrows():
str_columns += f"cast({row["column_name"]} as decimal(38,10)) as {row["column_name"]}" if row["data_type"] == "double" else row["column_name"]
str_columns += ","
str_columns = str_columns[:-1] # 最後のカンマを削除
query = f"""
select
{str_columns}
from {TABLE_NAME}
;
"""
df = wr.athena.read_sql_query(sql=query, database=DATABASE, s3_output=OUTPUT_LOCATION)
response = {"data":json.loads(df.to_json(orient='records'))}
return {
'statusCode':200,
'body': json.dumps(response)
}
except Exception as e:
print(e)
return {
'statusCode': 500,
'body': json.dumps({ 'error': 'faild' }),
}
おわり
今回は全てのテーブルで同じように動作させるためにこのような手段を取りましたが本来はあまり使わなそうな手段だと思います。
ですが、同じような悩みがあるかたの参考にしていただければ嬉しいです。
そして、この記事を書きながら思いました。
修正前はboto3でathenaを実行して結果をそのまま出力していましたが、今回はawswranglerを使っているのでうまいこと変換してくれていないかと。
忘れていなければ確認してみようと思います。
追記
やはりawsranglerの場合0.003の形で表示されていました...