LoginSignup
11
13

More than 1 year has passed since last update.

Athena(Presto)のエラーメッセージの原因の解決方法のまとめ(2022年版)

Last updated at Posted at 2022-12-06

弊社では各プロジェクトの大半がAWSに統一されているため、エンジニア以外の方が分析やログ確認などをされる際にAthenaなどを利用されることが多めです。

一方でAthena(Presto)ではエラーメッセージに対する解決策を調べようとするとStack Overflow上の英語のケースが多めだったり、エラー内容がエンジニア側からしても直観的ではない(瞬時に内容を把握してSQLの修正が効かない)ケースがあります。特にエンジニア以外の方からすると英語のStack Overflowなどよりも日本語で丁寧な解決方法があるとUXが良くなります(多分)。

弊社のAthenaをバックエンドで使ったBI上などでは英語のエラーメッセージに日本語のメッセージも併せて表示されたり解決策などを細かく表示したりしているのですが、その辺は世の中に記事として公開していた方がAthenaユーザーの皆さまにとって役立つのでは・・・と思い、Qiitaの記事にしておきます。

※公開に関しては上長から許可をいただいております。

注意書き

  • 日々AthenaやPrestoなどもアップデートされたりしているため、エラーメッセージが変わったり追加になったりは発生しています。そのためこの記事の内容は日々古くなっていく点はご容赦ください(気が向いたら来年以降などにまたアップデートされた形で記事にするかもしれません)。
    • ※タイミング悪いことに、この記事を書いている途中にAthenaのクエリエンジンのv3が公開されましたw しかもv3からPrestoではなくTrinoベースとなっています。本記事の内容はv2(Prestoベースの)時点でのものをベースとしています。
  • 基本的に社内で発生頻度の高いエラーなどが中心です。全てのエラーはカバーしているわけではない点もご容赦ください。
  • 内容に関してはこちらで誤解しているケースなどもあるかもしれません。ある程度は精査していますが、解決方法などを参考にしても解決しないケースなども結構あると思います。その際にはコメントなり編集リクエストなどでご指摘いただけますと幸いです(フィードバック内容は弊社BIへの設定にも使わせていただくため、弊社としても助かります)。

エラー一覧

All ARRAY elements must be the same type: <定義されている型>

Athena(Presto)では配列(ARRAY)の内の値の型は1つとして定義する必要があり、テーブル作成時などにarray<bigint>といったように指定されます。この状態でSQL上などで複数の型の値を含むようにして配列の作成や連結などを行ってしまうとこのエラーが発生します。

エラーメッセージの<定義されている型>の部分にはテーブル定義時に想定される値の型として指定されている型(bigintなど)が表示されます。

Array subscript is negative

配列(Array)の添え字([]の括弧で特定のインデックスを指定する記述)では負のインデックス(-1など)は指定することはできません。

Pythonなどだと-1を指定することで配列の末尾の要素に参照できたりしますがAthenaではそういった記述を行うことができません。

負のインデックスを指定して配列の末尾の方から要素を参照したい場合には負のインデックスの添え字の代わりにELEMENT_AT関数などを使う必要があります(こちらは負のインデックスが指定できます)。

Amazon Athena experienced an internal error while executing this query. Please contact AWS support for further assistance. You will not be charged for this query. We apologize for the inconvenience.

一時的なAthena側の内部エラーなので、リトライすればそのままのSQLで大体通ります。

Bytes scanned limit was exceeded

Athenaではフルスキャンなどで膨大なサイズに対してアクセスが走って大きく課金されないように一度のSQLでスキャンできるサイズの上限が設定できます。

一方でこのエラーが発生した場合には許容されているスキャンサイズの上限を超えてしまっています。

フルスキャンにならないようにするためのSQL内で対象テーブルのパーティションの指定による日付の絞り込み(where dt = '2022-01-01'といったような記述など)が漏れていないかなどを確認する必要があります。

もしスキャンサイズの上限が小さいと感じられる場合にはAthenaの管理をしているエンジニアの方などに連絡して上限設定を緩和してもらう必要があります。

All COALESCE operands must be the same type: <第一引数に指定されている値(カラム)の型>

COALESCEは欠損値を第二引数に指定された値で補完するための関数です。第一引数には対象のカラムや値を指定します。

このCOALESCE関数では第一引数と第二引数で型を統一する必要があります。たとえば第一引数に文字列の型のカラムを指定した場合、第二引数の補完値にも同じ型の値じゃないと補完ができないため文字列の値を指定する必要があります。

'[]' cannot be applied to <添え字が指定された値の型>, <添え字の型>

[]の括弧による添え字をサポートされていない型(整数など)へ設定した場合にこのエラーは発生します。

たとえば整数の型のカラムに対してany_int_column[10]みたいな記述や50[10]みたいな記述も行うことができません。

添え字をしている箇所が配列想定だったものの整数などの型の値になっていないかなどを確認する必要があります。

'演算子の記号' cannot be applied to <左辺の値の型>, <右辺の値の型>

=+などの演算子の記号を異なる型の値(カラム)同士に対して指定した場合に発生します(文字列と配列の値に対して演算子での計算などを行おうとした場合など)。

両辺の値の型を揃えるためにCAST関数で型変換(キャスト)を挟むか、もしくは別の変換用の関数などを挟む必要があります。

'演算子の記号' cannot be applied to interval day to second, integer

※前節と同じように型の不一致によるエラーですが、よくあるケースなので加筆しておきます。

DATE_DIff関数などを使って取得した値はinterval day to secondといった表記の特殊な型の値となり、直接整数などとは比較することができません。

これらの値に対して整数での比較を行いたい場合にはTO_MILLISECONDS関数を通してミリ秒の整数に変換したり、もしくはその値に対してさらに1000で除算したりして秒の値で比較したり・・・といった対応が必要になります。

'<演算子の記号>' cannot be applied to <左辺の型>, row(<rowの値の型>もしくは'<演算子の記号>' cannot be applied to row(<rowの値の型>, <右辺の型>

※前節と同じように型の不一致によるエラーですが、よくあるケースなので加筆しておきます。

Athena(Presto)では()の括弧を使って値を指定するとrow型の値として判定されます。

余分な()の括弧が記述されているケースもエラーになりますが、加えてよくありがちなケースとしてWHERE <対象のカラム> IN (10, 20, 30)みたいなIN句での記述をしようとしてうっかりWHERE <対象のカラム> = (10, 20, 30)といったような記述をしてしまっているとこのエラーが発生します。

例 : WHERE any_bigint_column = (2, 3)といった記述であれば'=' cannot be applied to bigint, row(integer,integer)といったようなエラーになります。

'<演算子の記号>' cannot be applied to varchar, interval year to monthもしくは'<演算子の記号>' cannot be applied to varchar, interval day to secondなど

Athena(Presto)では<DATEもしくはTIMESTAMPの型> + INTERVAL '<日数など>' DAYといったような記述で日数や月数、年数などの計算が行えます。

しかし計算対象の値がDATETIMESTAMPなどではなく日付の形式の文字列の型(VARCHARなど)の場合にはこのような計算は行えずこの節のエラーが発生します。

そういった場合には文字列の値をCAST関数やDATE関数などでDATETIMESTAMPなどの型へと変換する必要があります。

'<演算子の記号>' cannot be applied to integer, varcharもしくは'<演算子の記号>' cannot be applied to varchar, integer

※前節と同じように型の不一致によるエラーですが、よくあるケースなので加筆しておきます。

文字列と整数による比較によるエラーなのですが、弊社の場合日付の形式の文字列のカラムに対して右辺側でシングルクォーテーションが足りていない・・・といったケースでも発生していました。

例えばdate_column > 2022-01-01といったような記述の場合に発生します(先頭が2022といったような数値になっているのでAthena上で整数として判定されてしまいます)。この場合には右辺などの日付部分をシングルクォーテーションで囲ってあげることでエラーを回避できます(例 : date_column > '2022-01-01')。

'<対象のオペレーター>' cannot be applied to <対象の値の型>

対象の値に対して操作ができない対象のオペレーターの記号(+や-など)を指定した場合に発生します。

例えば整数などであれば+-*などのオペレーターの記号を使った計算を行えますが、文字列(VARCHARなど)の場合には-の記号などでは操作することができません。その場合には'-' cannot be applied to varcharといったようなエラーメッセージになります。

java.lang.Boolean cannot be cast to java.lang.Long

ログに真偽値(trueなど)が含まれている一方でテーブル側のカラムがBIGINTなどで定義されていると発生します。テーブル側もしくはログ側に手を加える必要があるため基本的にエンジニアとかの作業が必要になるケースが多めです。

ログ側でtrueなどと0や1などが混在している場合が少し厄介で、ログ側を補正するかもしくはどちらも受け付けてくれる型(文字列など)でカラムを定義してしまってSQL上でcastなどを通す必要があります。

Cannot cast array(<配列の値の型>) to <変換したい値>

CAST関数などを配列の値に指定し変換ができないケースに発生します。もし単一の配列内の整数や文字列などを参照したい場合には[]の括弧による配列のインデックス参照の記述が漏れていたり、もしくはUNNESTなどで配列を行列変換するなどの対応が必要になります(その他、配列操作系の関数を挟むなど)。

Cannot cast interval day to second to <dateもしくはtimestamp、bigintなどの型>

日付(DATE)や日時(TIMESTAMP)などの差分値(interval day to secondと呼ばれる各値で減算などをした際に得られる値)をDATETIMESTAMPなどの型へとキャストしようとした際に発生します。

基本的には差分値は直接timeなどへキャストするのではなく、TO_MILLISECONDS関数などでミリ秒に変換したり、その値を1000で除算したりして秒に変換して扱ったりなどをします(整数で値を取りたい場合もCAST関数などではなくTO_MILLISECONDSなどを使います)。

例 : TO_MILLISECONDS(time_1 - time_2) / 1000

Cannot cast timestamp to <intなどの整数の型>

日時の型(TIMESTAMP)の値をintなどの型へキャストしようとした際に発生します。

日時をUNIXTIMEなどで整数で扱いたい場合にはTO_UNIXTIMEなどの変換用の関数を通す必要があります。

Cannot cast <変換したい元の値の型> to char(<文字数>)

特定の値を固定長の文字列(CHAR)にキャストしようとした際に発生します。基本的にCAST関数でのキャストなどではCHARではなくVARCHARを指定する形で問題ないと思いますので、VARCHARを指定することでエラーを回避することができます。

Cannot cast <変換したい元の値の型> to DECIMAL

CAST関数を通す際にDECIMAL型を指定した場合に、DECIMAL型の引数が足りていない場合や引数に指定した桁数が実際の値に対して足りないなどの理由でキャストができない場合に発生します。

他のVARCHARBIGINTなどへのキャスト時には引数などは不要ですが、DECIMAL型の場合はCAST関数に指定する際には引数設定などが必要になるため注意が必要です。

Cannot cast <変換したい元の値の型> to map(<MAPのキーの型>, <MAPの値の型>)

何らかの型の値をMAP(辞書)の型へCAST関数などで変換出来なかった場合等に発生します。

MAPへの変換はCAST関数ではなくMAP関数、MAP_FROM_ENTRIES関数、MULTIMAP_FROM_ENTRIES関数、MAP_AGG関数などMAP型への変換用の関数が色々用意されているのでそちらを使うとこのエラーを回避できることがあります。

Cannot cast varbinary to varchar

バイナリデータから文字列へCAST関数などで型変換できない場合に発生します。

代わりにFROM_UTF8関数やTO_BASE64関数、TO_HEX関数などで必要な文字列に変換できるケースがあります。

Cannot cast '<対象値>' to INT

対象値を整数にキャストできない場合に発生します(シンプルな1010.5といった数値の文字列ではなく2022-01-01 10:30:50みたいな日時などの形式の文字列が指定された場合なども発生します)。

CAST関数ではなくTO_UNIXTIME関数など別の関数を使うことでこのエラーを回避できることがあります。

Cannot check if <対象の値やカラムの型> is BETWEEN <下限の指定値の型> and <上限の指定値の型>

WHERE句などで指定した対象の値やカラムの型に対して、BETWEENの指定で上限と下限に指定された値のいずれかの型が一致していない場合に発生します。

それぞれの値の型をCAST関数などで揃える必要があります。

なお、日付の文字列のカラム(パーティションなども含む)に対してBETWEEN句でうっかりクォーテーションが漏れている・・・みたいな場合も整数判定となって型の不一致が発生しているケースもぼちぼち発生していたりしています。

例 : any_date BETWEEN 2022-01-01 AND 2022-01-05

Cannot find partition.

Glueのクローラーとかが使われているテーブルで発生したケースがありました。恐らくパーティションの特定の日付のフォルダ等自体が存在せず、パーティションで途中で抜けが発生した場合などにそのパーティションを含む形でSQLを書くと発生するかと思われます。

ログが入らない日でもフォルダが作られるようにしておくとか、もしくはPARTITION PROJECTIONなどをテーブルに設定することで恐らく回避ができます(エンジニア寄りな対応が必要になります)。

Cannot nest aggregations inside aggregation '<外側の関数情報>': [<内側の関数情報>]

入れ子にできない集合関数(SUMAVG等)などを入れ子にした場合に発生します(例 : SUM(AVG(...)))。

基本的に集合関数では1つの関数を通した時点で複数の値(複数の行)では無く単一値となるため、複数の関数は反映できないのでSQLを見直す必要があります。

Cannot nest window functions inside aggregation '<外側の集合関数情報>': [<内側の窓関数情報>]

窓関数(ROW_NUMBERなど)を集合関数(SUMAVG等)内で入れ子にした場合に発生します(例 : AVG(ROW_NUMBER() ...))。

窓関数の結果の値に対してさらに集計処理が必要な場合には入れ子にするのではなくWITH句などでサブクエリ化する必要があります。

cannot recognize input near '<指定されたカラム名>' '<指定されたカラムの型>' 'その他情報' in column specification

テーブル作成時などに指定したカラム名(もしくは辞書のカラムのキー名)が受け付けられない文字列の場合に発生します(カラム名などの先頭にアンダースコアが付いているなど)。

カラム名などにクォートが付与されていない場合などに発生するため、このエラーの場合にはカラム名などに`の記号によってクォートを追加することでエラーを回避できることがあります。

Cannot unnest type: <指定された値の型情報>

UNNESTの行列変換をARRAYの配列やMAPの辞書のカラム等以外のサポートされていない型に対して実行した場合に発生します。ROW型(STRUCTの辞書のカラムに対してもSQLを通すとROW型として扱われたりします)などでも弾かれます。

もし対象のカラムに対して本当にUNNESTが必要な場合(カラム名指定ミスなどでは無い場合)、テーブル構造・ログ構造依存なのでSQLを調整して何とかする・・・とかは難しいエラーとなります。

All CASE results must be the same type: <必要な型>

CASE句の結果の各値(THENでの指定箇所)で複数の型の値が混在しています。各値の型は統一する必要があります。

CASE operand type does not match WHEN clause operand type: <左辺側の型> vs <右辺側の型>

CASE句のWHEN部分で指定した条件設定の左辺と右辺で型が一致しておらず比較ができない場合などに発生します(例 : 左辺が整数が右辺が文字列になっている場合など)。

キャスト処理などを挟んで型を統一する必要があります。

CASE WHEN clause must evaluate to a boolean (actual: <指定された実際の値の型>)

CASE句のWHEN部分は真偽値(BOOLEAN)になっている必要があります(真偽値以外の型の値が指定されていてエラーになっています)。

>=!=などのオペレーターでの比較結果は真偽値となるためそれらの比較処理を指定するか、もしくは真偽値を返す関数などに差し替えたり、0か1が設定される整数のカラムであればBOOLEANへのキャストを対応する必要があります。

Catalog <カタログ名> does not exist

AthenaではDBよりも上の階層としてデータカタログをSQL上で指定することができます。たとえば<カタログ名>.<DB名>.<テーブル名>.<カラム名>といったような階層でコロン区切りで指定することができます。

このカタログ名の指定部分に存在しないカタログ名が指定された場合にこのエラーが発生します。

※テーブル名を指定するべきSQLの箇所にカラム名まで含めて<DB名>.<テーブル名>.<カラム名>といった記述をしてしまった場合、SQL側では<カタログ名>.<DB名>.<テーブル名>という判定になり1つずつずれてしまうため結果的に対象のカタログ名のカタログが存在しない・・・といったエラーになっているケースでも発生します。

Column alias list has <指定されたカラム名の数> entries but '<エイリアスのテーブル名>' has <必要なカラム名の数> columns available

UNNESTCROSS JOINなどを使用した際に発生します。それらの記述箇所でAS テーブル名(各カラム名の指定)といった記述をした際に、括弧内の指定されたカラム数の数が実際に必要なカラム数と一致していない場合に発生します。

たとえばMAP型の辞書を扱う場合にはキーと値で2カラム分の指定が括弧内で必要になります(配列などを扱う場合と必要カラム数がずれます)。2件必要な状態で1件のみカラムが指定されている・・・といった場合に発生するため、カラム名の件数を調整する必要があります。

Column '<指定されたカラム名>' is ambiguous

JOINなどで複数のテーブルを連結した際などに、各テーブルで同名のカラムが存在し且つSQL上でテーブル名の指定をせずにカラム名単体で指定した際に発生します。

SQL側からどのテーブルのカラムを選択すれば良いか判断が付かないために発生するため、<テーブル名>.<カラム名>といったようにテーブル名を省略せずに明示すればこのエラーを回避できます。

Column '<指定されたカラム名>' cannot be resolved

SQL内で指定されたカラムが見つからない場合に発生します。タイプミスであったり、対象のテーブルが持っていないカラムであったりすると発生します。

また、WHERE句ではカラム指定部分でSELECT句でASでカラム名にエイリアスを設定した際のエイリアス名での指定が効かなかったりする(WHEREの方が先に評価される?)ので、WHERE句の中でエイリアスの名前を指定している場合などにも発生します。

GROUP BYと集合関数(COUNTなど)を組み合わせた結果のカラムを指定したい場合などにはWHERE句での指定の代わりにHAVING句の方で指定することでこのエラーを回避できることがあります。

Column '<指定されたカラム名>' not in GROUP BY clause

GROUP BYを使った場合にはSELECT句のカラム指定にはGROUP BYで指定したカラムもしくはCOUNTなどの集合関数を挟んだカラムのみ指定することができます。それ以外のカラムをSELECT句で指定している場合にこのエラーが発生します(SELECT句でアスタリスクなどを指定していて余分なカラムが指定されている場合でも発生します)。

また、SELECT句以外でもORDER BYの指定カラムでも同様のケースが発生することがあります。

SELECT句などで必要なカラムをGROUP BYかもしくは集合関数を挟むようにすればエラーを回避できますが、集計内容的にGROUP BYに含めたくない場合などには窓関数(WINDOW FUNCTION)を使うことでGROUP BYと同じようなことが実現できて且つ様々な他のカラムを使用できることがあります。

'<指定されたカラム>' must be an aggregate expression or appear in GROUP BY clause

こちらも前節と同じような条件で発生するエラーで、指定されたカラムがGROUP BYの中に指定されておらず、且つCOUNTなどの集合関数も挟まれていない場合などに発生します。解決方法も前節と同じでGROUP BYに含めるか集合関数を挟むか、もしくはGROUP BYの代わりに窓関数で代用できる場合には窓関数を使用するなどが挙げられます。

Database does not exist: <指定されたDB名>

指定されたDB名が見つからない場合に発生します。指定したDB名でタイプミスなどをしていないかなどを確認してください。カタログ名も指定している場合(catalog_name.db_nameといった形でコロン区切りでDB名を指定した場合など)にはそのカタログ内に対象のDBが存在しているかなども確認する必要があります。

DECIMAL precision must be in range [<許容可能な最小桁数>, <許容可能な最大桁数>]

DECIMAL型の引数の桁数の指定が許容可能な桁数範囲外になっている場合に発生します。桁数指定の引数の整数値を許容可能な範囲の桁数に調整する必要があります。

DECIMAL scale must be in range [0, precision]

DECIMAL型の指定で引数で指定した桁数指定が、必要な桁数よりも少なくなっている可能性があります。引数の桁数指定の整数を増やすなどの調整が必要になります。

Destination table '<指定されたテーブル名>' already exists. You may need to manually clean the data at location '<S3のパス>' before retrying. Athena will not delete data in your account.

CTASCREATE TABLE AS SELECT ...)などで指定したテーブル名が既に存在しテーブルが作成できない場合に発生します。

もし対象のテーブルが不要(置換したい場合など)には先にDROP TABLEでテーブルを削除しておくとこのエラーが発生しなくなります。

DIVISION_BY_ZERO: / by zero

/の記号を使った除算計算で分母側に0が含まれている場合に発生します。

分母側に指定したカラムで1行でも0が含まれていると発生しうるため、そういった場合には0の場合の分岐制御や置換処理などをSQL内に入れておく必要があります。0以外でも分母側で欠損値が含まれる・・・といった場合にはNULLIF関数などで欠損値を他の値に置換しておく必要があります。

Expression <不正なSQLの記述> is not of type ROW

指定されたSQL部分がROW型の扱いになっている(ROW型の値を生成するための()の括弧を使っていたり、.の記号によるROW型の値への参照など)一方で、対象の値が正常なROW型の値ではない場合などに発生します。

エラーメッセージで表示されている辺りのSQLの内容を見直す必要があります(型は正常か、余分な()などの括弧が記述されていないかなど)。

Failed to tokenize string [<対象の文字>] at offset [<対象の文字のインデックス>]

日付や日時への変換処理などを行おうとした際に指定した値が不正(日付に変換ができない形式に値がなっているなど)な場合などに発生します。

使用するべきもっと適した関数があればそちらを利用するか、もしくは一度文字列操作などで値を編集してから変換処理を挟むことで回避できることがあります。

Function <指定された関数名> not registered

Athenaで利用できない関数名が指定された場合に発生します。関数名などで誤字脱字などしていないかを確認し、もし問題がない場合にはAthena側でまだサポートされていない関数である可能性があります(Trino / Presto側で新しく追加されたばかりの関数など)。

Given correlated subquery is not supported

()の括弧を使ったサブクエリはWHERE句やJOINなどで使用できますが、そのサブクエリがそれ以外のサポートされていない箇所で使用された場合に発生します。

括弧を使ったサブクエリの代わりにWITH句を使ったサブクエリを利用するとこのエラーを回避できるケースがあります。

GROUP BY clause cannot contain aggregations, window functions or grouping operations: [<指定された関数情報>]

GROUP BY句には集合関数(MINCOUNTなど)や窓関数(OVERなど)等を含めることはできません。

それらの関数を事前に挟む必要がある場合にはWITH句などでサブクエリを使って関数を反映してから別途GROUP BYを使うなどの調整が必要になります。

The input strings to hamming_distance function must have the same length

HAMMING_DISTANCE関数で指定された第一引数の文字列の値もしくはカラムが同じ文字数に統一されていない場合に発生します。

文字数が異なる値同士で比較したい場合にはHAMMING_DISTANCE関数の代わりにLEVENSHTEIN_DISTANCE関数の使用が必要になります。

HAVING clause must evaluate to a boolean: actual type <実際の値の型>

HAVING句の記述は真偽値(BOOLEAN)になる必要がある一方で実際の指定では他の型の値(整数など)になっている場合に発生します。

=>=などの比較演算であれば結果は真偽値になるのでそれらを使うか、0か1を取るような整数の値であれば真偽値にキャストするか、もしくは他の真偽値を返却値する関数などを挟む必要があります。

Data is not JSONObject but java.lang.String with value <JSON形式の文字列の内容>

テーブルの型が配列や辞書などのカラムになっている一方で、実際のログの値はJSON形式の文字列になっている場合に発生します(JSONの値がクォーテーションで囲まれている場合など)。

テーブル側のカラムの型の指定と実際のログの内容が乖離している影響なので、ログ側をテーブル構造に合わせるか、もしくはテーブル側のカラムを文字列として宣言してSQL上でJSON関係の関数を挟んで扱うという対応が必要になります。

HIVE_BAD_DATA: Error parsing field value '<データの値>' for field <フィールド位置のインデックス>: For input string: "<データの値>"

CSVもしくはJSONのログ側で特定のフィールドの値でクォーテーションが足りていなかったり不正な改行、エスケープなどが含まれていることなどによって不正なデータが含まれてしまっている場合に発生します。

もしくはテーブルのカラムの型と実際のログの型が一致していない(整数のカラムに文字列のログが格納されている等)ケースや、対象のカラムで扱えない値がログに含まれているケースなどが存在する可能性があります(INT型の整数のカラムに対して22億を超えるような値がログに格納されておりオーバーフローしているなど)。

ログ側を調整するか、テーブル構造の変更などを行う必要があります。

Field <フィールド名>'s type <ログ側のParquetの対象のフィールドの型> in parquet file <ログファイルのS3のパス> is incompatible with type <テーブル側で定義されている型> defined in table schema

Parquetのログのテーブルで、特定のフィールドのParquet側の型とテーブル側で定義されている型が一致していない場合に発生します。

ログ側を調整するか、テーブル側の型の定義を調整する必要があります。

An error occurred (EntityNotFoundException) when calling the GetTable operation: Table <テーブル名> not found.

指定されたテーブルへ正常にアクセスできなかった際に発生します。
テーブル定義などが更新中のステータスなどで一時的にアクセスができないなどの理由が考えられます。

少し時間をおいて再実行するとエラーを回避できる可能性があります。

identifiers must not start with a digit; surround the identifier with double quotes

カタログ名、DB名、テーブル名、カラム名などが数字でスタートしており、且つSQL上でもクォーテーション無しで指定されている場合に発生します。

数字などをそれらの名前で使用したい場合にはダブルクォーテーションでそれらを囲むことでエラーを回避できることがあります。

IF condition must evaluate to a boolean (actual: <実際の値の型>)

IFの条件で指定された条件が真偽値(BOOLEAN)になっていない場合に発生します。

=>=などの比較演算では結果が真偽値になるのでそれらを使うか、もしくは真偽値を返却する関数を挟んだり真偽値へキャストするなどの調整が必要になります。

Incorrect number of parameters: expected <想定するパラメーター数> but found <実際のパラメーター数>

EXECUTE句などで指定しているパラメーター数が想定されるパラメーター数と一致していない場合に発生します。

登録されている設定などを確認してパラメーター数を合わせる必要があります。

Input type row(<キー名> <キーの型>, <値の名前> <値の型>) not supported

入力値としてROW型(キーと値を持つ型)の値を受け付けられない個所(関数の引数など)でROW型の値が指定されている場合に発生します(整数や文字列などを受け付ける箇所にROW型の値が指定されている場合など)。

※辞書のカラム(STRUCT)などもSQL実行時にはROW型としてAthenaでは扱われるため、辞書のカラム(もしくは辞書を格納した配列のカラムなど)の個所が影響している可能性があります。

Value cannot be cast to date: <変換しようとした値>

日付の型(DATE)への型変換(キャスト)に失敗した場合に発生します。

変換しようとした文字列などが日付のフォーマットになっていない(日時や月のフォーマットになっているケースなども含む)可能性があります。

※もし対象が日時の文字列(例 : 2022-01-01 10:00:00)であればSUBSTR関数関数で時間部分を取り除いた文字列を取得することで対応することができます。

例 : SELECT SUBSTR(日時のカラム, 1, 10)

もし対象が月の文字列(例 : 2022-01)であれば、-01といった文字列を加える形で連結することで対応することができます。

例 : SELECT 日時のカラム || '-01'

Value cannot be cast to timestamp: <変換しようとした値>

文字列などから日時の値(TIMESTAMP)へキャストできない場合に発生します。指定しようとしている値は文字列であれば2022-01-01といった日付の形式の文字列や2022-01-03 10:30:50といった日時の形式の文字列などが変換できます。2022-01といった年月の文字列などはエラーとなります。

そういったキャストができない文字列になっている場合には||の記号で文字列を追加したり、SUBSTR関数で置換をしたり、もしくは正規表現などで変換ができるフォーマットに整えたりする必要があります。

例 : CAST(month_column || '-01' AS TIMESTAMP)

Invalid format: "<実際の値>"

日付変換などでフォーマットの指定を行う箇所で、実際の値とフォーマットがずれている場合などに発生します。

値に対して指定した記号やフォーマット用の文字列が正しいか、サポートされているフォーマットの文字列なのかなどを確認する必要があります。

'<入力値>' is not a valid DATE field

日付(DATE)型を受け付ける箇所(関数の引数など)でDATE型以外の値が指定されています。

キャストが漏れていて文字列の日付の値を指定してしまっていたり、もしくは別のカラムを指定してしまっているなどの理由が考えられます。

Row is not a valid JSON Object - JSONException: Expected a '<想定される記号など>' after a key at <キーの位置> [character <対象位置の文字数> line <対象行>]

JSONのログで不正なログ(JSONの途中で途切れている破損ログなど)が含まれている場合に発生します。

ログ側を修正するか、もしくはテーブル定義時の設定で破損ログの行を無視する設定の追加などが必要になります(ignore.malformed.jsonの設定など)。

Row is not a valid JSON Object - JSONException: A JSONObject text must end with '}' at <}の記号が来るべき位置> [character <対象の文字の位置> line <対象の行番号>]

JSONのログで}で終わるべき位置で}の記号がログ破損などで欠落している場合に発生します。

ログ側を修正するか、もしくはテーブル定義時の設定で破損ログの行を無視する設定の追加などが必要になります(ignore.malformed.jsonの設定など)。

Row is not a valid JSON Object - JSONException: Expected a ',' or '}' at <,もしくは}が来るべき位置> [character <対象の文字の位置> line <対象の行数>]

JSONのログで,もしくは}の記号が来るべき位置に別の文字が来ているか、もしくはそれらの記号がログ破損などによって不足している場合に発生します。

ログ側を修正するか、もしくはテーブル定義時の設定で破損ログの行を無視する設定の追加などが必要になります(ignore.malformed.jsonの設定など)。

Row is not a valid JSON Object - JSONException: Expected a ',' or ']' at <,もしくは]が来るべき位置> [character <対象の文字の位置> line <対象の行数>]

JSONのログで,]の記号が来るべき箇所に別の文字が来ているか、もしくはそれらの記号がログ破損などによって不足している場合に発生します。

ログ側を修正するか、もしくはテーブル定義時の設定で破損ログの行を無視する設定の追加などが必要になります(ignore.malformed.jsonの設定など)。

Row is not a valid JSON Object - JSONException: Unterminated string at <対象の位置> [character <対象の文字の位置> line <対象の行数>]

こちらもJSONのログの破損などで発生します。

ログ側を修正するか、もしくはテーブル定義時の設定で破損ログの行を無視する設定の追加などが必要になります(ignore.malformed.jsonの設定など)。

Invalid number of arguments for '<対象の関数名>' function

対象の関数の引数の数が足りていないもしくは過剰になっている場合に発生します。ドキュメントなどを確認して正確な引数の数を調べて調整する必要があります。

Invalid reference to output projection attribute from ORDER BY aggregation

サポートされていない記述となる、ORDER BY句の中での集合関数の利用などがされている可能性があります(例 : ORDER BY句の中でCOUNT関数を使うなど)。

IN value and list items must be the same type: <カラムの型>

WHERE句のIN句で指定した値の型が対象のカラムの型と一致していない場合に発生します。

IN句で指定した値の型は正しいか(数値のカラムに対して文字列でIN句の値を指定していないか等)、もしくは必要に応じてCAST関数などでカラムの値の型変換などを検討してください。

Left side of LIKE expression must evaluate to a varchar (actual: <実際のカラムの型>)

文字列検索などで使用するLIKE句の左辺側の対象のカラムの指定に文字列(VARCHAR)以外の型カラムを指定した場合に発生します。

指定したカラムをミスしていないか、もしくは必要に応じて文字列のカラムへとキャストするなどの対応を検討してください。

Left side of logical expression must evaluate to a boolean (actual: <実際の値の型>)

比較演算などでのANDORなどで条件を繋げた際等に左辺側で真偽値(BOOLEAN)が必要な箇所に別の型の値が来ている場合に発生します(ANDなどの左側が整数の値になっているケースなど)。

=>=などの演算子を使った場合結果は真偽値になるのでそれらを使うか、キャストや真偽値を返す関数などに調整する必要があります。

Right side of logical expression must evaluate to a boolean (actual: <実際の値の型>)

比較演算などでのANDORなどで条件を繋げた際等に右辺側で真偽値(BOOLEAN)が必要な箇所に別の型の値が来ている場合に発生します(ANDなどの右側が整数の値になっているケースなど)

=>=などの演算子を使った場合結果は真偽値になるのでそれらを使うか、キャストや真偽値を返す関数などに調整する必要があります。

Escape character must be followed by '%', '_' or the escape character itself

LIKE句などで使用する特定の文字によるエスケープの指定は、その文字の直後は%もしくは_の記号、もしくはエスケープで指定した文字自体になっている必要があります。それ以外の文字が指定されている場合にこのエラーが発生します。

Pattern for LIKE expression must evaluate to a varchar (actual: <実際の値の型>)

LIKE句で指定した条件のパターン部分が文字列以外になっている場合に発生します。SQLの記述や文法でミスしていないかを確認する必要があります。

たとえばIN句のように()の括弧をうっかりLIKE句で使ったりしている(例 : LIKE ('%検索したい文字列%'))とROW型として判定されて文字列扱いにならないためにこのエラーになります。

mismatched input '<不正な指定>'. Expecting: '<想定される指定>'

mismatched inputから始まる各種エラーは基本的にSQLで受け付けられない記述が来ている場合の文法エラーで発生します。

例えばBYのキーワードが来るべき箇所に別の記述が来ていて文法エラーになっている・・・みたいなケースに発生します。

mismatched inputの直後に受け付けられない不正な指定部分の記述が表示されます。

受け付けられるものはExpecting:の後に一覧が表示されます。

例えばExpecting: 'BY'というエラーメッセージであればBYのキーワードのみ受け付けられる・・・といった形になります。

記号などもExpecting:以降に含まれるケースがあります。例えばExpecting: ')', 'ARRAY'と来ていれば)の閉じ括弧もしくはARRAYのキーワードのみを受け付けられる・・・といった具合になります。

その他Expecting:部分には<>の括弧での特殊な記述が来ることもあります(例 : <EOF><identifier>など)。

大雑把に以下にそれらの意味を記述しておきます。

  • <EOF> -> SQLの末尾(終了)部分を受け付けます。
  • <query> -> WITH句などでのサブクエリやCTASなどでクエリを受け付けます。
  • <type> -> キャスト処理などの箇所で型の指定を受け付けます。
  • <expression> -> 少し自信がないのですが、比較表現などの各種表現の記述を受け付ける・・・感じでしょうか?
  • <identifier> -> カタログ名、DB名、テーブル名、カラム名、キー名などの特定要素の識別用の記述を受け付けます。

Multiple columns returned by subquery are not yet supported. Found <サブクエリ結果のカラム数>

()の括弧を使ったサブクエリでは複数のカラムを返却する指定はサポートされておらず、そういった際にこのエラーが発生します。

サブクエリのSELECT文で1つのカラムのみを返却するように調整するか、もしくはサブクエリで複数カラムの指定が必要な場合にはWITH句を使ったサブクエリの利用などを検討してください。

name expected at the position <悪影響の出ている文字の位置> of '<該当箇所の型情報>' but '<不正な値>' is found.

ログが不正な場合、もしくはログとテーブル構造のずれなどによって発生します。例えばSTRUCTの辞書のカラム部分に辞書として扱えない形のデータがログに含まれている・・・といったケースに発生します。

基本的にはログの修正もしくはテーブル側のカラム構造の修正などが必要になります。

<指定されたサポートされていない日付のフォーマット> not supported in date format string

日付の型(DATE)の値のフォーマット処理に指定された文字列(%記号と組み合わせる文字列など)にサポートされていない文字列が指定された場合に発生します。

Athenaのバージョンに応じてPrestoもしくはTrinoのドキュメントを確認し、サポートされている文字列に調整する必要があります。

Prestoのドキュメント:

Trinoのドキュメント:

Queries of this type are not supported

割とこのエラー行番号なども表示されず厄介なのですが、SQLで文法ミスがあるか、もしくはテーブル名やカラム名などの指定でAthena(PrestoやTrino)での予約語(tabledateなど、そのまま使えないキーワード)が使われている場合であったり、もしくは閉じ括弧が不足している・・・などのケースなど雑多な理由で発生します。

テーブル名などに対する予約語による影響であればそれらをダブルクォーテーションなどで囲むことでこのエラーを回避できることがあります。

Unsupported Hive type: timestamp with time zone.

タイムゾーン(時差)設定付きのTIMESTAMPがサポートされていない個所で利用されている場合に発生します。

このエラーはCTASCREATE TABLE ... AS SELECT ...)内のSQLでNOW関数などのタイムスタンプの値を取得する際などに発生します。

回避策は何とも見つからず(もしかしたら良い方法があるのかもしれませんが・・・)、弊社の場合独自関数とか設ける形で対応しています。

No page sink provider for catalog '対象のカタログ名'

基本的にAthena側の一時的な問題によって発生するため、時間を置いてリトライすると基本的に解決します。

null value at position <位置のインデックス>

関数の引数などでNULLが指定できない箇所にNULLが指定されている場合に発生します。

エラーメッセージ内のインデックスは0からスタートするため、0であれば第一引数、1であれば第二引数といった具合に問題の引数位置を確認して修正などを行う必要があります。

Only one sql statement is allowed. Got: <SQL内容>

Athenaで複数のSQLを同時に指定することはできないため、複数のSQLをセミコロン区切りで指定した際に発生します。

セミコロンがSQLの末尾以外に配置されていないかなどを確認して、単一のSQLになるように調整する必要があります。

There is a mismatch between the table and partition schemas. The types are incompatible and cannot be coerced. The columns in table '<テーブル情報>' do not match with partition '<パーティション情報>'

テーブルのパーティション設定に不整合が発生している場合などに発生します。テーブル定義やログ側のパーティションの構造の調整などをする必要があります。

Permission denied on S3 path: <S3のパス>

Athena側から対象のS3に対してアクセスなどをする権限がない場合に発生します。AWSの権限周りの調整が必要です。

An error occurred (InvalidRequestException) when calling the StartQueryExecution operation: PreparedStatement <指定されたPREPARE句で登録した> was not found in workGroup <ワークグループ名>

指定されたPREPARE句で登録しておいたSQLの名称が現在使用しているワークグループ内で見つからない場合に発生します。

使用しているワークグループは正しいか、指定したSQLの登録名などが合っているか(誤字脱字などをしていないか)などを確認する必要があります。

Query cancelled by user

ユーザーによってクエリ実行中に実行をキャンセルした場合にこのエラーが発生します。

Query exhausted resources at this scale factor

一時的にAthenaのリソースが不足して不安定になったか、もしくはSQLの記述で極端に処理負荷のかかる内容になっている場合に発生します。

再度実行しても発生する場合にはSQL内容を調整する必要があります。

Query timeout

SQLクエリの実行が長時間され続けてタイムアウトして停止した際に発生します。

タイムアウト時間の設定を調整するか、SQL内容を調整する必要があります。

Pattern has <正規表現内で設定されているグループ数> groups. Cannot access group <指定されたグループ位置>

正規表現で指定されたグループ位置が正規表現内で設定されているグループ数を超えている(対象のグループが存在しない)場合に発生します。

正規表現の文字列側にグループを増やすか、もしくは指定しているグループ位置にミスが無いかなどを確認する必要があります。

Result types for IF must be the same: <第二引数に指定された値の型> vs <第三引数に指定された値の型>

IF関数で指定された第二引数と第三引数の値の型は一致させる必要がありますが、一致していない場合にこのエラーが発生します。

第二引数と第三引数の指定部分の内容を確認して調整する必要があります。

SELECT * not allowed in queries without FROM clause

SELECT句に*のアスタリスク記号を指定した場合、且つFROM句の指定が存在しない場合に発生します。

FROM句によるテーブルの指定を追加するか、もしくはアスタリスク以外の固定値などであればFROM句無しでSQLを実行することができます。

例 : SELECT 100 AS a, 200 AS b

For SELECT DISTINCT, ORDER BY expressions must appear in select list

SELECT DISTINCT(1つ目のカラム, 2つ目のカラム, ...)といった複数のカラムをDISTINCTで指定する構文で、且つORDER BYを併用する場合にはDISTINCT以外のカラム指定個所にORDER BYで指定したカラムが必要になります(カラム指定がDISTINCTのみなどになっているとこのエラーが発生します)。

例 : SELECT DISTINCT(a, b), b FROM ... ORDER BY b

Signature expired: <時間関係の情報>

Athenaがタイムアウトした場合に発生します。再実行しても発生する場合にはSQL内容を調整する必要があります。

別途存在するタイムアウトのエラーに対して、こちらのエラーはAthenaのタイムアウト設定を調整して改善するか・・・は未確認です。

The specified key does not exist. (<AWSサービスなどの情報>)

若干Athenaの謎のエラー感がありますが、弊社の場合は再実行したら直りました。AWS側で何らか瞬間的に悪影響が出たなどの可能性があります。

Subquery uses '<問題のカラム名>' which must appear in GROUP BY clause

SELECT句の中などでサブクエリを使用しているカラムが存在し、且つそのカラムがGROUP BY句に含まれていないとSELECT句で指定出来ない条件の場合に発生します。

可能であればGROUP BYで指定しているカラムを追加するか、もしくはサブクエリで参照しているカラム内容を調整するなどの必要があります。GROUP BY句での指定が難しい場合には窓関数でGROUP BYに近いことをすることで要件を満たせることがあります。

Scalar sub-query has returned multiple rows

WITH句ではない単一のスカラー値(単一の整数など)の返却が必要なサブクエリの個所で複数行の値が返却されているサブクエリが存在します。

対象のサブクエリでLIMIT 1といった記述や各関数を使って対象を1行に制限することでこのエラーを回避することができます。

Column name not specified at position <対象の位置>.

CTASCREATE TABLE ... AS SELECT ...)もしくは別のSQLで記述されたSQLのカラム指定部分が不正な場合に発生します。

指定されたテーブル名やカラム名などが正常か確認する必要があります。

Unexpected parameters (<指定された引数の型情報>) for function <対象の関数名>. Expected: <想定される(受け付けられる)関数の記述や引数情報>

対象の関数に指定された引数が不正な場合に発生します。

引数の数が正常か、構文のフォーマットが合っているか、指定したカラムや値の型がExpected:以降で記述されている内容と合っているかなどを確認して調整する必要があります(必要に応じて公式ドキュメントなどの確認が必要になります)。

Schema <指定されたDB名もしくはテーブル名> does not exist

指定されたDB名もしくはテーブル名が存在しない場合に発生します。

もしテーブル名単体で指定している箇所が引っかかっている場合、選択しているDBが想定と違っているなどの理由でDB名の指定も追加することでこのエラーを回避できるケースがあります(例 : any_db.any_table)。

Table <テーブル名> does not exist

指定されたテーブル名が存在しない場合に発生します。

もしテーブル名単体で指定している箇所が引っかかっている場合、選択しているDBが想定と違っているなどの理由でDB名の指定も追加することでこのエラーを回避できるケースがあります(例 : any_db.any_table)。もしくはテーブル再生成などをしている場合は少し完了まで待ってから再実行する必要があります。

Table '<テーブル名>' not found

こちらも前節と同じような理由で指定されたテーブルが見つからない場合に発生します。解決方法も前節と基本同じです。

Table already exists: '<指定されたテーブル名>'

CREATE TABLECTASなども含む)に指定されたテーブル名が既に存在する場合に発生します。

別のテーブル名にするか、もしくは対象のテーブルが不要であれば一回DROP TABLEなどでテーブルを削除する必要があります。

Table already exists with a different schema: '<指定されたテーブル名>'

CTASなどでのテーブル作成処理で、指定されたテーブルと同名のテーブルが存在する場合に発生します。同時に同じ名前でのテーブル作成のSQLを投げた際などに稀に発生します。

別のテーブル名にするか、もしくは対象のテーブルが不要であれば一回DROP TABLEなどでテーブルを削除するか、もしくは誤って2回投げてしまった場合などには既にテーブルは作成されているので2回目のエラーは無視する形での対応が考えられます。

Table being modified concurrently

SQL実行中に別のSQLでテーブル構造の更新などが走りSQLが正常に完了しなかった場合に発生します。

基本的に少し待てばテーブル構造の更新は終わるので、その後にSQLを再実行すれば(テーブル構造変更によってSQLが引っかからなければ)このエラーを回避できます。

Target directory already exists: <指定されたS3のパス>

UNLOAD句などで指定したS3のディレクトリパスがすでに存在しデータの保存が出来ない場合に発生します。一度該当のディレクトリを削除してから処理を行う必要があります。

Types are not comparable with <関数名>: <比較対象の1つ目の引数値の型> vs <比較対象の2つ目の引数値の型>

特定の関数で2つの引数の値の比較などがされる場合に、それぞれの引数の型が一致しておらず比較ができない場合に発生します(NULLIF関数などで発生しうる形になります)。

いずれかの引数の値の型を調整して型を統一する必要があります。

Unable to locate credentials

基本的に何も変更していなくともこのエラーが発生したことがあります。基本的にAWS内部の問題?のようで、再実行したりすると普通にエラーなく通ったりしています。

Unexpected IOException (of type java.io.IOException): S3 path is null

パーティション関係のディレクトリが一部存在しないか、もしくは何らかGlueのクローラーなどで悪影響が出ていてSQLが投げられないように発生します。

Glueの内容を確認したり再実行などするか、S3上のディレクトリの状況を確認するか、もしくはPartition Projectionを利用するかなどの対応が必要になります。

UNION query has different number of fields: <1つ目のカラム数>, <2つ目のカラム数>

UNION句で垂直方向にSELECT結果を統合する際に、1つ目と2つ目の各統合対象でカラム数が一致していない場合に発生します。

どちらかのSELECT結果のカラム数に合うようにSQL上のカラムの指定数を調整する必要があります。

Unknown type: <指定された型>

CAST関数などによる型のキャストで処理ができない型が指定されている場合に発生します。指定した型がキャスト用に使える型なのか等を確認してください。

STRING型はCREATE TABLEなどの際には使用しますがCAST関数などでは使用できません。文字列にキャストしたい場合にはSTRING型の代わりにVARCHAR型などを指定する必要があります。

DECIMAL型などは特殊で型の指定時に引数を指定する必要があります。

WHERE clause cannot contain aggregations, window functions or grouping operations: [<不正な指定の関数などの情報>]

WHERE句に集合関数(COUNTなど)や窓関数(OVERなどを使うもの)、もしくはGROUP BYなどでグループ化したカラムの記述がされている場合に発生します(WHERE句の中ではそれらを使うことができません)。

もし集計値などが条件指定で必要な場合にはWHERE句の代わりにHAVING句を、GROUP BYで指定したカラムの利用などが必要な場合にはWITH句でサブクエリを挟むことで対応ができるケースがあります。

WHERE clause must evaluate to a boolean: actual type <実際の値の型>

WHERE句の指定は真偽値(BOOLEAN)を指定する必要がある一方で別の型の値が指定されている場合に発生します(整数など)。

>==などでの比較演算子での記述などは結果が真偽値になるのでそちらを使用するか、もしくは0か1などの整数であれば真偽値へキャストを行ったり、別の真偽値を返却値する関数を利用するなどの調整が必要です。

Window frame start cannot be UNBOUNDED FOLLOWING

窓関数のフレームの指定(ROWSもしくはRANGE)の開始値にUNBOUNDED FOLLOWING(終了値側の指定)を行っている場合に発生します。

BETWEENを使って終了値側に指定するか、もしくは別のキーワード(UNBOUNDED PRECEDINGCURRENT ROWなどの開始値側で指定できるキーワード)と間違えていないかなどを確認する必要があります。

Window frame RANGE PRECEDING is only supported with UNBOUNDED

窓関数のRANGEによるフレームの指定は、Athena(Presto)ではUNBOUNDEDUNBOUNDED PRECEDINGなど)のみをサポートしている一方で、<前方向への調整値> PRECEDING<後方向への調整値> FOLLOWINGなどのサポートされていない指定を行ってしまっている場合に発生します。

サポートされていないのは仕方が無いため、必要な場合にはSQLの工夫などで対応する必要があります。

Window function <指定された窓関数名> requires an OVER clause

窓関数を使用する場合にはOVER句もセットで使う必要がありますが、OVER句の指定が漏れている場合に発生します。

OVER句で必要な各設定を追加することがエラーを回避できます。

AVG関数での例 : AVG(sales) OVER(PARTITION BY device_type ORDER BY dt ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)

WITH column alias list has <エイリアスに指定されたカラム数> entries but WITH query(ratecount) has <クエリ結果で得られるカラム数> columns

WITH句(サブクエリのWITH句ではなくUNNESTなどを使う際のカラム指定を必要とするWITH句)で指定されたカラム名の数とSQL結果で得られたカラム数が一致していない場合に発生します。

例えば配列に対するUNNESTであればカラム名は1件の指定で動いたりしますが、辞書に対するUNNESTであればキーと値それぞれの2カラム分の名称をWITH句で指定しないとエラーにななります。

指定しているカラム名の数をエラーメッセージで表示される数字に合わせて調整するか、もしくはSQL内容を調整する必要があります。

WITH query name '<重複しているテーブル名>' specified more than once

サブクエリのWITH句で同じ名前のテーブル名が複数回指定されている場合に発生します。

同じ名前は設定できないため別のテーブル名を指定してください。

11
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
13