9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

athenaでjsonへのselectを攻略する

Last updated at Posted at 2020-11-16

athenaでjsonのカラムから値を抽出したい

必要な時にさっとクエリを書けるようにしたいので、よく使うパターンを例と共にまとめる。

with句について

with 名前 as (select)

として実行することで、付けた名前のテーブルのようにクエリが書ける。
この記事の例ではテーブルを作ってデータを入れる代わりに、with句を使って一時的なテーブルを作ってクエリを試していく。
with句と実行したいselect文を一緒に実行すればクエリを試すことができる。

ユースケース①: jsonの内容を同じ行に展開したい場合

key-valueで値の入ったjsonのカラムから値を取得したい場合のユースケース

クエリの書き方

json_extract_scalarjson_extractを使う。
配列やmapの抽出にはjson_extract_scalarは使えないので、代わりにjson_extractを使う。

SELECT
  json_extract_scalar({jsonのカラム名}, '$.{jsonのキー名}') AS {付けたい名前}
FROM dataset
SELECT
  json_extract({jsonのカラム名}, '$.{jsonのキー名}') AS {付けたい名前}
FROM dataset

例A: keyでvalueを取り出す

使用するデータセット例

some_mapにkey-valueでjsonを入れてある

WITH dataset AS (
  SELECT
    CAST('john' AS JSON) AS name,
    CAST(12345 AS JSON) AS count,
    CAST(MAP(ARRAY['location', 'role'], ARRAY['Tokyo','engineer']) AS JSON) AS some_map
)
SELECT * FROM dataset

実行結果


name	count	some_map
john	12345	{u'role': u'engineer', u'location': u'Tokyo'}

jsonからrole,locationを取り出すクエリ

クエリ
SELECT
  name,
  count,
  json_extract_scalar(some_map, '$.role') AS role,
  json_extract_scalar(some_map, '$.location') AS location
FROM dataset
実行結果
name	count	role	location
john	12345	engineer	Tokyo

例B: jsonから配列を取り出す

1つのjson1カラムのみのデータにおいて、配列の要素を取り出してみる。
json_extract_scalarは使わずjson_extractを使う

使用するデータセット例

クエリ
WITH dataset AS (
  SELECT '{"name": "John",
           "role": "engineer",
           "projects": [{"name":"project1", "completed":false},{"name":"project2", "completed":true}]}'
    AS col
)
select * from dataset
実行結果
col
{"name": "John", "role": "engineer", "projects": [{"name":"project1", "completed":false},{"name":"project2", "completed":true}]}

jsonの配列を取り出すクエリ

SELECT json_extract(blob, '$.projects') AS item
FROM dataset

実行結果

item
[{"completed":false,"name":"project1"},{"completed":true,"name":"project2"}]

例C: 配列からN番目の要素を取り出す

json_array_get({配列}, {index}) で取り出すことができる

使用するデータセット例

クエリ
WITH dataset AS (
  SELECT '{"name": "John",
           "role": "engineer",
           "projects": [{"name":"project1", "completed":false},{"name":"project2", "completed":true}]}'
    AS col
)

select * from dataset
実行結果
col
{"name": "John", "role": "engineer", "projects": [{"name":"project1", "completed":false},{"name":"project2", "completed":true}]}

配列の0番目の要素を取り出す

SELECT json_array_get(json_extract(col, '$.projects'), 0) AS item
FROM dataset
item 
{"completed":false,"name":"project1"}

ユースケース②:jsonのカラムの内容を複数行に展開したい場合

配列で入っているjsonのカラムの内容を展開したい場合のユースケース

クエリの書き方

unsetを使用する。
ぱっと見で理解し難いので例を参考にして欲しい。

SELECT {好きな名前}[{jsonkey}] 
FROM dataset, UNNEST({jsonの配列のカラム名}) AS t({好きな名前})

使用するデータセット例

peopleという1カラムに、jsonが配列で入っている

クエリ

WITH
dataset AS (
  SELECT
     ARRAY[
      MAP(ARRAY['first', 'last', 'age'],ARRAY['Bob', 'Smith', '40']),
      MAP(ARRAY['first', 'last', 'age'],ARRAY['Jane', 'Doe', '30']),
      MAP(ARRAY['first', 'last', 'age'],ARRAY['Billy', 'Smith', '8'])
     ] AS people
  )
select * from dataset

実行結果

people 
[{last=Smith, first=Bob, age=40}, {last=Doe, first=Jane, age=30}, {last=Smith, first=Billy, age=8}]

unnestで分解する

peopleというjsonの配列が入ったカラムをunnestし、
namesというエンティティ(first,last,ageの3つのkey-valueをもつ)に展開し、
names['first']でnamesからvalueを取得する。

SELECT names['first'] AS first_name,
  names['last'] AS last_name,
  names['age'] AS age 
FROM dataset, UNNEST(people) AS t(names)

実行結果

first_name	last_name	age
Bob	Smith	40
Jane	Doe	30
Billy	Smith	8

参考文献

athenaの公式ドキュメントくらいしか参考になるものがないため、頑張って読んで、載っているクエリを試してみて理解するのが一番良さそう。
https://docs.aws.amazon.com/athena/latest/ug/extracting-data-from-JSON.html
https://docs.aws.amazon.com/athena/latest/ug/flattening-arrays.html

9
5
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
9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?