

# 배열 쿼리
<a name="querying-arrays"></a>

Amazon Athena를 사용하면 배열을 만들고, 연결하고, 다른 데이터 형식으로 변환한 다음 필터링 및 평면화하고 정렬할 수 있습니다.

**Topics**
+ [배열 생성](creating-arrays.md)
+ [문자열 및 배열 연결](concatenating-strings-and-arrays.md)
+ [배열 데이터 형식 변환](converting-array-data-types.md)
+ [배열 길이 찾기](finding-lengths.md)
+ [배열 요소에 액세스](accessing-array-elements.md)
+ [중첩 배열 평면화](flattening-arrays.md)
+ [하위 쿼리에서 배열 생성](creating-arrays-from-subqueries.md)
+ [배열 필터링](filtering-arrays.md)
+ [배열 정렬](sorting-arrays.md)
+ [배열과 함께 집계 함수 사용](arrays-and-aggregation.md)
+ [배열을 문자열로 변환](converting-arrays-to-strings.md)
+ [배열을 사용하여 맵 생성](arrays-create-maps.md)
+ [복잡한 데이터 형식의 배열 쿼리](rows-and-structs.md)

# 배열 생성
<a name="creating-arrays"></a>

Athena에서 배열 리터럴을 구축하려면 `ARRAY` 키워드 뒤에 `[ ]` 괄호를 사용하고 쉼표로 구분된 배열 요소를 포함합니다.

## 예시
<a name="examples"></a>

이 쿼리는 네 개 요소로 이루어진 배열 하나를 생성합니다.

```
SELECT ARRAY [1,2,3,4] AS items
```

다음 결과가 반환됩니다.

```
+-----------+
| items     |
+-----------+
| [1,2,3,4] |
+-----------+
```

이 쿼리는 두 개의 배열을 생성합니다.

```
SELECT ARRAY[ ARRAY[1,2], ARRAY[3,4] ] AS items
```

다음 결과가 반환됩니다.

```
+--------------------+
| items              |
+--------------------+
| [[1, 2], [3, 4]]   |
+--------------------+
```

호환되는 형식의 선택된 열에서 배열을 생성하려면 다음 예제와 같은 쿼리를 사용합니다.

```
WITH
dataset AS (
  SELECT 1 AS x, 2 AS y, 3 AS z
)
SELECT ARRAY [x,y,z] AS items FROM dataset
```

이 쿼리가 반환하는 값:

```
+-----------+
| items     |
+-----------+
| [1,2,3]   |
+-----------+
```

다음 예에서는 두 개의 배열이 선택되고 환영 메시지로 반환됩니다.

```
WITH
dataset AS (
  SELECT
    ARRAY ['hello', 'amazon', 'athena'] AS words,
    ARRAY ['hi', 'alexa'] AS alexa
)
SELECT ARRAY[words, alexa] AS welcome_msg
FROM dataset
```

이 쿼리가 반환하는 값:

```
+----------------------------------------+
| welcome_msg                            |
+----------------------------------------+
| [[hello, amazon, athena], [hi, alexa]] |
+----------------------------------------+
```

키-값 페어의 배열을 만들려면 이 예에서와 같이 키 배열 뒤에 값 배열을 가져오는 `MAP` 연산자를 사용하세요.

```
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
```

이 쿼리가 반환하는 값:

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

# 문자열 및 배열 연결
<a name="concatenating-strings-and-arrays"></a>

문자열 연결과 배열 연결은 비슷한 기법을 사용합니다.

## 문자열 연결
<a name="concatenating-strings"></a>

두 문자열을 연결하려면 다음 예시처럼 이중 파이프 `||` 연산자를 사용합니다.

```
SELECT 'This' || ' is' || ' a' || ' test.' AS Concatenated_String
```

이 쿼리가 반환하는 값:


****  

| \$1 | Concatenated\$1String | 
| --- | --- | 
| 1 |  `This is a test.`  | 

`concat()` 함수를 사용하여 동일한 결과를 얻을 수 있습니다.

```
SELECT concat('This', ' is', ' a', ' test.') AS Concatenated_String
```

이 쿼리가 반환하는 값:


****  

| \$1 | Concatenated\$1String | 
| --- | --- | 
| 1 |  `This is a test.`  | 

`concat_ws()` 함수를 사용하여 첫 번째 인수에 지정된 구분 기호에 문자열을 연결할 수 있습니다.

```
SELECT concat_ws(' ', 'This', 'is', 'a', 'test.') as Concatenated_String
```

이 쿼리가 반환하는 값:


****  

| \$1 | Concatenated\$1String | 
| --- | --- | 
| 1 |  `This is a test.`  | 

점을 사용하여 문자열 데이터 유형의 두 열을 연결하려면 큰따옴표를 사용하여 두 열을 참조하고 작은따옴표를 사용하여 점을 하드코딩된 문자열로 묶습니다. 열이 문자열 데이터 유형이 아닌 경우 `CAST("column_name" as VARCHAR)`를 사용하여 먼저 열을 캐스팅할 수 있습니다.

```
SELECT "col1" || '.' || "col2" as Concatenated_String
FROM my_table
```

이 쿼리가 반환하는 값:


****  

| \$1 | Concatenated\$1String | 
| --- | --- | 
| 1 |  `col1_string_value.col2_string_value`  | 

## 배열 연결
<a name="concatenating-arrays"></a>

동일한 기법을 사용하여 배열을 연결할 수 있습니다.

여러 배열을 연결하려면 이중 파이프 `||` 연산자를 사용합니다.

```
SELECT ARRAY [4,5] || ARRAY[ ARRAY[1,2], ARRAY[3,4] ] AS items
```

이 쿼리가 반환하는 값:


****  

| \$1 | 항목 | 
| --- | --- | 
| 1 |  `[[4, 5], [1, 2], [3, 4]]`  | 

여러 배열을 하나의 배열으로 결합하려면 이중 파이프 연산자나 `concat()` 함수를 사용합니다.

```
WITH
dataset AS (
  SELECT
    ARRAY ['Hello', 'Amazon', 'Athena'] AS words,
    ARRAY ['Hi', 'Alexa'] AS alexa
)
SELECT concat(words, alexa) AS welcome_msg
FROM dataset
```

이 쿼리가 반환하는 값:


****  

| \$1 | welcome\$1msg | 
| --- | --- | 
| 1 |  `[Hello, Amazon, Athena, Hi, Alexa]`  | 

`concat()` 기타 문자열 함수에 대한 자세한 내용은 Trino 설명서의 [문자열 함수 및 연산자](https://trino.io/docs/current/functions/string.html)를 참조하세요.

# 배열 데이터 형식 변환
<a name="converting-array-data-types"></a>

배열의 데이터를 지원되는 데이터 형식으로 변환하려면 `CAST` 연산자를 사용합니다(예: `CAST(value AS type)`). Athena는 기본 Presto 데이터 형식을 모두 지원합니다.

```
SELECT
   ARRAY [CAST(4 AS VARCHAR), CAST(5 AS VARCHAR)]
AS items
```

이 쿼리가 반환하는 값:

```
+-------+
| items |
+-------+
| [4,5] |
+-------+
```

다음 예와 같이 키-값 페어 요소로 두 개의 배열을 만들고 JSON으로 변환하여 연결합니다.

```
SELECT
   ARRAY[CAST(MAP(ARRAY['a1', 'a2', 'a3'], ARRAY[1, 2, 3]) AS JSON)] ||
   ARRAY[CAST(MAP(ARRAY['b1', 'b2', 'b3'], ARRAY[4, 5, 6]) AS JSON)]
AS items
```

이 쿼리가 반환하는 값:

```
+--------------------------------------------------+
| items                                            |
+--------------------------------------------------+
| [{"a1":1,"a2":2,"a3":3}, {"b1":4,"b2":5,"b3":6}] |
+--------------------------------------------------+
```

# 배열 길이 찾기
<a name="finding-lengths"></a>

`cardinality` 함수는 다음 예에서와 같이 배열의 길이를 반환합니다.

```
SELECT cardinality(ARRAY[1,2,3,4]) AS item_count
```

이 쿼리가 반환하는 값:

```
+------------+
| item_count |
+------------+
| 4          |
+------------+
```

# 배열 요소에 액세스
<a name="accessing-array-elements"></a>

배열 요소에 액세스하려면 다음 예에서와 같이 `[]` 연산자(1은 첫 번째 요소를, 2는 두 번째 요소를 지정하는 방식)를 사용합니다.

```
WITH dataset AS (
SELECT
   ARRAY[CAST(MAP(ARRAY['a1', 'a2', 'a3'], ARRAY[1, 2, 3]) AS JSON)] ||
   ARRAY[CAST(MAP(ARRAY['b1', 'b2', 'b3'], ARRAY[4, 5, 6]) AS JSON)]
AS items )
SELECT items[1] AS item FROM dataset
```

이 쿼리가 반환하는 값:

```
+------------------------+
| item                   |
+------------------------+
| {"a1":1,"a2":2,"a3":3} |
+------------------------+
```

주어진 위치(인덱스 위치라고 함)에서 배열 요소에 액세스하려면 `element_at()` 함수를 사용하여 배열 이름과 인덱스 위치를 지정합니다.
+ 인덱스가 0보다 큰 경우, `element_at()`은 지정된 요소를 배열의 처음부터 끝까지 계산하여 반환합니다. 이는 `[]` 연산자처럼 작동합니다.
+ 인덱스가 0보다 작은 경우, `element_at()`은 배열의 끝에서부터 시작까지 계산하여 요소를 반환합니다.

다음 쿼리는 배열 `words`를 만들고, 거기에서 `first_word`로 첫 번째 요소 `hello`를 선택하고, `middle_word`로 두 번째 요소 `amazon`을(배열의 끝에서부터 계산), `last_word`로 세 번째 요소 `athena`를 선택합니다.

```
WITH dataset AS (
  SELECT ARRAY ['hello', 'amazon', 'athena'] AS words
)
SELECT
  element_at(words, 1) AS first_word,
  element_at(words, -2) AS middle_word,
  element_at(words, cardinality(words)) AS last_word
FROM dataset
```

이 쿼리가 반환하는 값:

```
+----------------------------------------+
| first_word  | middle_word | last_word  |
+----------------------------------------+
| hello       | amazon      | athena     |
+----------------------------------------+
```

# 중첩 배열 평면화
<a name="flattening-arrays"></a>

중첩 배열로 작업할 때 중첩 배열 요소를 단일 배열로 확장하거나 배열을 여러 행으로 확장해야 하는 경우가 많습니다.

## 평면화 함수 사용
<a name="flattening-arrays-flatten-function"></a>

중첩된 배열의 요소를 여러 값의 단일 배열로 평면화하려면 `flatten` 함수를 사용합니다. 이 쿼리는 배열의 각 요소에 대한 행을 반환합니다.

```
SELECT flatten(ARRAY[ ARRAY[1,2], ARRAY[3,4] ]) AS items
```

이 쿼리가 반환하는 값:

```
+-----------+
| items     |
+-----------+
| [1,2,3,4] |
+-----------+
```

## CROSS JOIN 및 UNNEST 사용
<a name="flattening-arrays-cross-join-and-unnest"></a>

배열을 여러 행으로 평면화하려면 다음 예제에서와 같이 `UNNEST` 연산자와 함께 `CROSS JOIN`을 사용합니다.

```
WITH dataset AS (
  SELECT
    'engineering' as department,
    ARRAY['Sharon', 'John', 'Bob', 'Sally'] as users
)
SELECT department, names FROM dataset
CROSS JOIN UNNEST(users) as t(names)
```

이 쿼리가 반환하는 값:

```
+----------------------+
| department  | names  |
+----------------------+
| engineering | Sharon |
+----------------------|
| engineering | John   |
+----------------------|
| engineering | Bob    |
+----------------------|
| engineering | Sally  |
+----------------------+
```

키-값 페어의 배열을 평면화하려면 다음 예제에서와 같이 선택한 키를 열로 이동합니다.

```
WITH
dataset AS (
  SELECT
    'engineering' as department,
     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 names['first'] AS
 first_name,
 names['last'] AS last_name,
 department FROM dataset
CROSS JOIN UNNEST(people) AS t(names)
```

이 쿼리가 반환하는 값:

```
+--------------------------------------+
| first_name | last_name | department  |
+--------------------------------------+
| Bob        | Smith     | engineering |
| Jane       | Doe       | engineering |
| Billy      | Smith     | engineering |
+--------------------------------------+
```

직원 목록에서 합산 점수가 가장 높은 직원을 선택합니다. `UNNEST`은(는) 기본 조인 연산자라서 묵시적이므로 앞에 `CROSS JOIN`을(를) 붙이지 않고 `FROM` 절에 사용할 수 있습니다.

```
WITH
dataset AS (
  SELECT ARRAY[
    CAST(ROW('Sally', 'engineering', ARRAY[1,2,3,4]) AS ROW(name VARCHAR, department VARCHAR, scores ARRAY(INTEGER))),
    CAST(ROW('John', 'finance', ARRAY[7,8,9]) AS ROW(name VARCHAR, department VARCHAR, scores ARRAY(INTEGER))),
    CAST(ROW('Amy', 'devops', ARRAY[12,13,14,15]) AS ROW(name VARCHAR, department VARCHAR, scores ARRAY(INTEGER)))
  ] AS users
),
users AS (
 SELECT person, score
 FROM
   dataset,
   UNNEST(dataset.users) AS t(person),
   UNNEST(person.scores) AS t(score)
)
SELECT person.name, person.department, SUM(score) AS total_score FROM users
GROUP BY (person.name, person.department)
ORDER BY (total_score) DESC
LIMIT 1
```

이 쿼리가 반환하는 값:

```
+---------------------------------+
| name | department | total_score |
+---------------------------------+
| Amy  | devops     | 54          |
+---------------------------------+
```

직원 목록에서 개별 점수가 가장 높은 직원을 선택합니다.

```
WITH
dataset AS (
 SELECT ARRAY[
   CAST(ROW('Sally', 'engineering', ARRAY[1,2,3,4]) AS ROW(name VARCHAR, department VARCHAR, scores ARRAY(INTEGER))),
   CAST(ROW('John', 'finance', ARRAY[7,8,9]) AS ROW(name VARCHAR, department VARCHAR, scores ARRAY(INTEGER))),
   CAST(ROW('Amy', 'devops', ARRAY[12,13,14,15]) AS ROW(name VARCHAR, department VARCHAR, scores ARRAY(INTEGER)))
 ] AS users
),
users AS (
 SELECT person, score
 FROM
   dataset,
   UNNEST(dataset.users) AS t(person),
   UNNEST(person.scores) AS t(score)
)
SELECT person.name, score FROM users
ORDER BY (score) DESC
LIMIT 1
```

이 쿼리가 반환하는 값:

```
+--------------+
| name | score |
+--------------+
| Amy  | 15    |
+--------------+
```

### CROSS JOIN 및 UNNEST 고려 사항
<a name="flattening-arrays-cross-join-and-unnest-considerations"></a>

`UNNEST`가 쿼리에 있는 하나 이상의 배열에 사용되고 배열 중 하나가 `NULL`인 경우 쿼리는 행을 반환하지 않습니다. 빈 문자열인 배열에 `UNNEST`를 사용하면 빈 문자열이 반환됩니다.

예를 들어 다음 쿼리에서는 두 번째 배열이 null이므로 쿼리는 행을 반환하지 않습니다.

```
SELECT 
    col1, 
    col2 
FROM UNNEST (ARRAY ['apples','oranges','lemons']) AS t(col1)
CROSS JOIN UNNEST (ARRAY []) AS t(col2)
```

다음 예제에서는 두 번째 배열이 빈 문자열을 포함하도록 수정됩니다. 각 행에 대해 쿼리는 `col1`의 값을 반환하고 `col2`의 값에 대해 빈 문자열을 반환합니다. 첫 번째 배열의 값이 반환되려면 두 번째 배열의 빈 문자열이 필요합니다.

```
SELECT 
    col1, 
    col2 
FROM UNNEST (ARRAY ['apples','oranges','lemons']) AS t(col1)
CROSS JOIN UNNEST (ARRAY ['']) AS t(col2)
```

# 하위 쿼리에서 배열 생성
<a name="creating-arrays-from-subqueries"></a>

행 모음에서 배열을 만듭니다.

```
WITH
dataset AS (
  SELECT ARRAY[1,2,3,4,5] AS items
)
SELECT array_agg(i) AS array_items
FROM dataset
CROSS JOIN UNNEST(items) AS t(i)
```

이 쿼리가 반환하는 값:

```
+-----------------+
| array_items     |
+-----------------+
| [1, 2, 3, 4, 5] |
+-----------------+
```

행 집합에서 고유한 값의 배열을 만들려면 `distinct` 키워드를 사용합니다.

```
WITH
dataset AS (
  SELECT ARRAY [1,2,2,3,3,4,5] AS items
)
SELECT array_agg(distinct i) AS array_items
FROM dataset
CROSS JOIN UNNEST(items) AS t(i)
```

이 쿼리는 다음 결과를 반환합니다. 순서는 보장되지 않습니다.

```
+-----------------+
| array_items     |
+-----------------+
| [1, 2, 3, 4, 5] |
+-----------------+
```

`array_agg` 함수 사용에 대한 자세한 내용을 알아보려면 Trino 설명서의 [Aggregate functions](https://trino.io/docs/current/functions/aggregate.html)(집계 함수)를 참조하세요.

# 배열 필터링
<a name="filtering-arrays"></a>

필터 조건과 일치하는 행 모음에서 배열을 만듭니다.

```
WITH
dataset AS (
  SELECT ARRAY[1,2,3,4,5] AS items
)
SELECT array_agg(i) AS array_items
FROM dataset
CROSS JOIN UNNEST(items) AS t(i)
WHERE i > 3
```

이 쿼리가 반환하는 값:

```
+-------------+
| array_items |
+-------------+
| [4, 5]      |
+-------------+
```

다음 예와 같이 요소 중 하나에 특정 값(예: 2)이 포함되어 있는지 여부에 따라 배열을 필터링합니다.

```
WITH
dataset AS (
  SELECT ARRAY
  [
    ARRAY[1,2,3,4],
    ARRAY[5,6,7,8],
    ARRAY[9,0]
  ] AS items
)
SELECT i AS array_items FROM dataset
CROSS JOIN UNNEST(items) AS t(i)
WHERE contains(i, 2)
```

이 쿼리가 반환하는 값:

```
+--------------+
| array_items  |
+--------------+
| [1, 2, 3, 4] |
+--------------+
```

## `filter` 함수 사용
<a name="filtering-arrays-filter-function"></a>

```
 filter(ARRAY [list_of_values], boolean_function)
```

`ARRAY` 표현식의 `filter` 함수를 사용하여 *boolean\$1function*이 true인 *list\$1of\$1values*에 항목의 하위 집합인 새 배열을 만듭니다. `filter` 함수는 *UNNEST* 함수를 사용할 수 없는 경우에 유용할 수 있습니다.

다음 예제에서는 `[1,0,5,-1]` 배열에서 0보다 큰 값으로 필터링합니다.

```
SELECT filter(ARRAY [1,0,5,-1], x -> x>0)
```

**결과**  
`[1,5]`

다음 예제에서는 `[-1, NULL, 10, NULL]` 배열에서 null이 아닌 값으로 필터링합니다.

```
SELECT filter(ARRAY [-1, NULL, 10, NULL], q -> q IS NOT NULL)
```

**결과**  
`[-1,10]`

# 배열 정렬
<a name="sorting-arrays"></a>

일련의 행에서 고유한 값의 정렬된 배열을 만들려면 다음 예제와 같이 [array\$1sort](https://prestodb.io/docs/current/functions/array.html#array_sort) 함수를 사용합니다.

```
WITH
dataset AS (
  SELECT ARRAY[3,1,2,5,2,3,6,3,4,5] AS items
)
SELECT array_sort(array_agg(distinct i)) AS array_items
FROM dataset
CROSS JOIN UNNEST(items) AS t(i)
```

이 쿼리가 반환하는 값:

```
+--------------------+
| array_items        |
+--------------------+
| [1, 2, 3, 4, 5, 6] |
+--------------------+
```

배열을 여러 행으로 확장하는 방법에 관한 자세한 내용은[중첩 배열 평면화](flattening-arrays.md) 단원을 참조하세요.

# 배열과 함께 집계 함수 사용
<a name="arrays-and-aggregation"></a>
+ 배열 내에서 값을 추가하려면 다음 예에서와 같이 `SUM`을 사용합니다.
+ 배열 내에서 여러 행을 집계하려면 `array_agg`를 사용합니다. 자세한 내용은 [하위 쿼리에서 배열 생성](creating-arrays-from-subqueries.md)을 참조하세요.

**참고**  
Athena 엔진 버전 2부터 집계 함수에 대해 `ORDER BY`가 지원됩니다.

```
WITH
dataset AS (
  SELECT ARRAY
  [
    ARRAY[1,2,3,4],
    ARRAY[5,6,7,8],
    ARRAY[9,0]
  ] AS items
),
item AS (
  SELECT i AS array_items
  FROM dataset, UNNEST(items) AS t(i)
)
SELECT array_items, sum(val) AS total
FROM item, UNNEST(array_items) AS t(val)
GROUP BY array_items;
```

마지막 `SELECT` 문에서 `sum()` 및 `UNNEST`를 사용하는 대신 다음 예제와 같이 `reduce()`를 사용하여 처리 시간과 데이터 전송을 줄일 수 있습니다.

```
WITH
dataset AS (
  SELECT ARRAY
  [
    ARRAY[1,2,3,4],
    ARRAY[5,6,7,8],
    ARRAY[9,0]
  ] AS items
),
item AS (
  SELECT i AS array_items
  FROM dataset, UNNEST(items) AS t(i)
)
SELECT array_items, reduce(array_items, 0 , (s, x) -> s + x, s -> s) AS total
FROM item;
```

위 쿼리는 다음과 같은 결과를 반환합니다. 반환되는 결과의 순서는 보장되지 않습니다.

```
+----------------------+
| array_items  | total |
+----------------------+
| [1, 2, 3, 4] | 10    |
| [5, 6, 7, 8] | 26    |
| [9, 0]       | 9     |
+----------------------+
```

# 배열을 문자열로 변환
<a name="converting-arrays-to-strings"></a>

하나의 배열을 단일 문자열로 변환하려면 `array_join` 함수를 사용합니다. 다음의 독립형 예제에서는 별칭이 지정된 `words`라는 배열을 포함한 `dataset`라는 테이블을 생성합니다. 이 쿼리는 `array_join`을 사용해 `words`의 배열 요소를 조인하고, 공백으로 이들을 분리한 다음, 별칭이 지정된 `welcome_msg`라는 열에 최종 문자열을 반환합니다.

```
WITH
dataset AS (
  SELECT ARRAY ['hello', 'amazon', 'athena'] AS words
)
SELECT array_join(words, ' ') AS welcome_msg
FROM dataset
```

이 쿼리가 반환하는 값:

```
+---------------------+
| welcome_msg         |
+---------------------+
| hello amazon athena |
+---------------------+
```

# 배열을 사용하여 맵 생성
<a name="arrays-create-maps"></a>

맵(Maps)은 Athena에서 사용할 수 있는 데이터 형식으로 구성된 키 값 페어입니다. 맵을 만들려면 `MAP` 연산자를 사용하고, 그리로 두 개의 배열을 전달합니다. 첫 번째는 열(키) 이름이고 두 번째는 값입니다. 배열의 모든 값은 같은 형식이어야 합니다. 맵 값 배열 요소 중 일부가 다른 형식이어야 하는 경우, 나중에 변환하면 됩니다.

## 예시
<a name="examples"></a>

이 예제는 데이터 세트에서 사용자를 선택합니다. `MAP` 연산자를 사용하고 그리로 두 개의 배열을 전달합니다. 첫 번째 배열에는 "first", "last" 및 "age"와 같은 열 이름 값이 포함됩니다. 두 번째 배열은 "Bob", "Smith", "35"와 같은 각 열의 값으로 구성됩니다.

```
WITH dataset AS (
  SELECT MAP(
    ARRAY['first', 'last', 'age'],
    ARRAY['Bob', 'Smith', '35']
  ) AS user
)
SELECT user FROM dataset
```

이 쿼리가 반환하는 값:

```
+---------------------------------+
| user                            |
+---------------------------------+
| {last=Smith, first=Bob, age=35} |
+---------------------------------+
```

이 예제에서와 같이 뒤에 `[key_name]`이 있는 필드 이름을 선택하여 `Map` 값을 검색할 수 있습니다.

```
WITH dataset AS (
 SELECT MAP(
   ARRAY['first', 'last', 'age'],
   ARRAY['Bob', 'Smith', '35']
 ) AS user
)
SELECT user['first'] AS first_name FROM dataset
```

이 쿼리가 반환하는 값:

```
+------------+
| first_name |
+------------+
| Bob        |
+------------+
```

# 복잡한 데이터 형식 및 중첩 구조의 배열 쿼리
<a name="rows-and-structs"></a>

소스 데이터는 흔히 복잡한 데이터 형식 및 중첩 구조의 배열로 구성됩니다. 이 단원의 예는 Athena 쿼리를 사용하여 요소의 데이터 형식을 변경하고, 배열 내의 요소를 찾고, 키워드를 찾는 방법을 보여줍니다.

**Topics**
+ [`ROW` 생성](creating-row.md)
+ [`CAST`를 사용하여 배열의 필드 이름 변경](changing-row-arrays-with-cast.md)
+ [`.` 표기법을 사용하여 배열 필터링](filtering-with-dot.md)
+ [중첩된 값이 포함된 배열 필터링](filtering-nested-with-dot.md)
+ [`UNNEST`를 사용하여 배열 필터링](filtering-with-unnest.md)
+ [`regexp_like`를 사용하여 배열에서 키워드 찾기](filtering-with-regexp.md)

# `ROW` 생성
<a name="creating-row"></a>

**참고**  
이 섹션의 예제는 작업할 샘플 데이터를 만드는 수단으로 `ROW`를 사용합니다. Athena 내에서 테이블을 쿼리한다면 데이터 소스로부터 이미 `ROW` 데이터 형식을 작성했으므로 따로 작성할 필요가 없습니다. `CREATE_TABLE`을 사용하면 Athena가 내부에 `STRUCT`를 정의하고 표를 데이터로 채우고 데이터 세트의 각 행에 `ROW` 데이터 형식을 만듭니다. 기본 `ROW` 데이터 형식은 지원되는 모든 SQL 데이터 형식의 명명된 필드로 구성됩니다.

```
WITH dataset AS (
 SELECT
   ROW('Bob', 38) AS users
 )
SELECT * FROM dataset
```

이 쿼리가 반환하는 값:

```
+-------------------------+
| users                   |
+-------------------------+
| {field0=Bob, field1=38} |
+-------------------------+
```

# `CAST`를 사용하여 배열의 필드 이름 변경
<a name="changing-row-arrays-with-cast"></a>

`ROW` 값을 포함하는 배열에서 필드 이름을 변경하기 위해 `ROW` 선언을 `CAST`할 수 있습니다.

```
WITH dataset AS (
  SELECT
    CAST(
      ROW('Bob', 38) AS ROW(name VARCHAR, age INTEGER)
    ) AS users
)
SELECT * FROM dataset
```

이 쿼리가 반환하는 값:

```
+--------------------+
| users              |
+--------------------+
| {NAME=Bob, AGE=38} |
+--------------------+
```

**참고**  
위에서는 `name`을 Presto에서의 형식인 `VARCHAR`로 선언합니다. `CREATE TABLE` 문 내에 이 `STRUCT`를 선언하는 경우, Hive가 데이터 형식을 `String`으로 정의하므로 `String` 형식을 사용합니다.

# `.` 표기법을 사용하여 배열 필터링
<a name="filtering-with-dot"></a>

다음 예에서는 점 `.` 표기법을 사용하여 AWS CloudTrail 로그 테이블의 `userIdentity` 열에서 `accountId` 필드를 선택합니다. 자세한 내용은 [AWS CloudTrail 로그 쿼리](cloudtrail-logs.md)를 참조하세요.

```
SELECT
  CAST(useridentity.accountid AS bigint) as newid
FROM cloudtrail_logs
LIMIT 2;
```

이 쿼리가 반환하는 값:

```
+--------------+
| newid        |
+--------------+
| 112233445566 |
+--------------+
| 998877665544 |
+--------------+
```

값의 배열을 쿼리하려면 다음 쿼리를 실행합니다.

```
WITH dataset AS (
  SELECT ARRAY[
    CAST(ROW('Bob', 38) AS ROW(name VARCHAR, age INTEGER)),
    CAST(ROW('Alice', 35) AS ROW(name VARCHAR, age INTEGER)),
    CAST(ROW('Jane', 27) AS ROW(name VARCHAR, age INTEGER))
  ] AS users
)
SELECT * FROM dataset
```

다음 결과를 반환합니다.

```
+-----------------------------------------------------------------+
| users                                                           |
+-----------------------------------------------------------------+
| [{NAME=Bob, AGE=38}, {NAME=Alice, AGE=35}, {NAME=Jane, AGE=27}] |
+-----------------------------------------------------------------+
```

# 중첩된 값이 포함된 배열 필터링
<a name="filtering-nested-with-dot"></a>

큰 배열에는 흔히 중첩된 구조가 포함되며, 그 안에서 값을 필터링하거나 검색할 수 있어야 합니다.

중첩된 `BOOLEAN` 값이 포함된 값의 배열에 데이터 집합을 정의하려면 다음 쿼리를 실행합니다.

```
WITH dataset AS (
  SELECT
    CAST(
      ROW('aws.amazon.com', ROW(true)) AS ROW(hostname VARCHAR, flaggedActivity ROW(isNew BOOLEAN))
    ) AS sites
)
SELECT * FROM dataset
```

다음 결과를 반환합니다.

```
+----------------------------------------------------------+
| sites                                                    |
+----------------------------------------------------------+
| {HOSTNAME=aws.amazon.com, FLAGGEDACTIVITY={ISNEW=true}}  |
+----------------------------------------------------------+
```

그런 다음, 그 요소의 `BOOLEAN` 값을 필터링하고 액세스하려면 계속해서 점 `.` 표기법을 사용합니다.

```
WITH dataset AS (
  SELECT
    CAST(
      ROW('aws.amazon.com', ROW(true)) AS ROW(hostname VARCHAR, flaggedActivity ROW(isNew BOOLEAN))
    ) AS sites
)
SELECT sites.hostname, sites.flaggedactivity.isnew
FROM dataset
```

이 쿼리는 중첩된 필드를 선택하고 다음 결과를 반환합니다.

```
+------------------------+
| hostname       | isnew |
+------------------------+
| aws.amazon.com | true  |
+------------------------+
```

# `UNNEST`를 사용하여 배열 필터링
<a name="filtering-with-unnest"></a>

중첩된 구조를 포함하는 배열을 하위 요소 중 하나로 필터링하려면 `UNNEST` 연산자로 쿼리를 실행합니다. `UNNEST`에 대한 자세한 내용은 [중첩 배열 평면화](flattening-arrays.md)을 참조하세요.

예를 들어 이 쿼리는 데이터 세트에서 사이트의 호스트 이름을 찾아냅니다.

```
WITH dataset AS (
  SELECT ARRAY[
    CAST(
      ROW('aws.amazon.com', ROW(true)) AS ROW(hostname VARCHAR, flaggedActivity ROW(isNew BOOLEAN))
    ),
    CAST(
      ROW('news.cnn.com', ROW(false)) AS ROW(hostname VARCHAR, flaggedActivity ROW(isNew BOOLEAN))
    ),
    CAST(
      ROW('netflix.com', ROW(false)) AS ROW(hostname VARCHAR, flaggedActivity ROW(isNew BOOLEAN))
    )
  ] as items
)
SELECT sites.hostname, sites.flaggedActivity.isNew
FROM dataset, UNNEST(items) t(sites)
WHERE sites.flaggedActivity.isNew = true
```

다음 결과가 반환됩니다.

```
+------------------------+
| hostname       | isnew |
+------------------------+
| aws.amazon.com | true  |
+------------------------+
```

# `regexp_like`를 사용하여 배열에서 키워드 찾기
<a name="filtering-with-regexp"></a>

다음의 예는 [regexp\$1like](https://prestodb.io/docs/current/functions/regexp.html) 함수를 사용하여 배열 내부 요소 내에서 키워드에 대한 데이터 집합을 검색하는 방법을 보여줍니다. 이 함수는 평가할 정규 표현식 패턴 또는 파이프(\$1)로 구분된 용어 목록을 입력으로 사용하며 패턴을 평가하고 지정된 문자열이 해당 패턴을 포함하고 있는지 판단합니다.

정규 표현식 패턴은 문자열 내에 포함되어 있어야 하고, 문자열과 반드시 일치할 필요는 없습니다. 전체 문자열을 일치시키려면 패턴의 시작 부분을 ^로, 끝부분을 \$1로 묶으세요(예: `'^pattern$'`).

호스트 이름과 `flaggedActivity` 요소가 포함된 사이트 배열을 고려하세요. 이 요소에는 여러 개의 `MAP` 요소가 포함된 `ARRAY`가 포함되며, 각기 다른 인기 키워드와 인기도가 나열됩니다. 이 배열에서 `MAP` 내의 특정 키워드를 찾고자 한다고 가정해 보겠습니다.

이 데이터 세트에서 특정 키워드를 갖는 사이트를 검색하려면 유사한 SQL `LIKE` 연산자 대신 `regexp_like`을(를) 사용하는데, 다수의 키워드를 검색할 때는 `regexp_like`이(가) 더욱 효율적이기 때문입니다.

**Example 예제 1: `regexp_like` 사용하기**  
이 예제의 쿼리는 `regexp_like` 함수를 사용하여 배열 내부의 값에 있는 `'politics|bigdata'`(이)라는 용어를 검색합니다.  

```
WITH dataset AS (
  SELECT ARRAY[
    CAST(
      ROW('aws.amazon.com', ROW(ARRAY[
          MAP(ARRAY['term', 'count'], ARRAY['bigdata', '10']),
          MAP(ARRAY['term', 'count'], ARRAY['serverless', '50']),
          MAP(ARRAY['term', 'count'], ARRAY['analytics', '82']),
          MAP(ARRAY['term', 'count'], ARRAY['iot', '74'])
      ])
      ) AS ROW(hostname VARCHAR, flaggedActivity ROW(flags ARRAY(MAP(VARCHAR, VARCHAR)) ))
   ),
   CAST(
     ROW('news.cnn.com', ROW(ARRAY[
       MAP(ARRAY['term', 'count'], ARRAY['politics', '241']),
       MAP(ARRAY['term', 'count'], ARRAY['technology', '211']),
       MAP(ARRAY['term', 'count'], ARRAY['serverless', '25']),
       MAP(ARRAY['term', 'count'], ARRAY['iot', '170'])
     ])
     ) AS ROW(hostname VARCHAR, flaggedActivity ROW(flags ARRAY(MAP(VARCHAR, VARCHAR)) ))
   ),
   CAST(
     ROW('netflix.com', ROW(ARRAY[
       MAP(ARRAY['term', 'count'], ARRAY['cartoons', '1020']),
       MAP(ARRAY['term', 'count'], ARRAY['house of cards', '112042']),
       MAP(ARRAY['term', 'count'], ARRAY['orange is the new black', '342']),
       MAP(ARRAY['term', 'count'], ARRAY['iot', '4'])
     ])
     ) AS ROW(hostname VARCHAR, flaggedActivity ROW(flags ARRAY(MAP(VARCHAR, VARCHAR)) ))
   )
 ] AS items
),
sites AS (
  SELECT sites.hostname, sites.flaggedactivity
  FROM dataset, UNNEST(items) t(sites)
)
SELECT hostname
FROM sites, UNNEST(sites.flaggedActivity.flags) t(flags)
WHERE regexp_like(flags['term'], 'politics|bigdata')
GROUP BY (hostname)
```
이 쿼리는 다음 두 사이트를 반환합니다.  

```
+----------------+
| hostname       |
+----------------+
| aws.amazon.com |
+----------------+
| news.cnn.com   |
+----------------+
```

**Example 예제 2: `regexp_like` 사용하기**  
다음 예의 쿼리는 검색어와 일치하는 사이트의 총 인기 점수를 `regexp_like` 함수로 합산한 다음, 가장 높은 순서에서 가장 낮은 순서로 정렬합니다.  

```
WITH dataset AS (
  SELECT ARRAY[
    CAST(
      ROW('aws.amazon.com', ROW(ARRAY[
          MAP(ARRAY['term', 'count'], ARRAY['bigdata', '10']),
          MAP(ARRAY['term', 'count'], ARRAY['serverless', '50']),
          MAP(ARRAY['term', 'count'], ARRAY['analytics', '82']),
          MAP(ARRAY['term', 'count'], ARRAY['iot', '74'])
      ])
      ) AS ROW(hostname VARCHAR, flaggedActivity ROW(flags ARRAY(MAP(VARCHAR, VARCHAR)) ))
    ),
    CAST(
      ROW('news.cnn.com', ROW(ARRAY[
        MAP(ARRAY['term', 'count'], ARRAY['politics', '241']),
        MAP(ARRAY['term', 'count'], ARRAY['technology', '211']),
        MAP(ARRAY['term', 'count'], ARRAY['serverless', '25']),
        MAP(ARRAY['term', 'count'], ARRAY['iot', '170'])
      ])
      ) AS ROW(hostname VARCHAR, flaggedActivity ROW(flags ARRAY(MAP(VARCHAR, VARCHAR)) ))
    ),
    CAST(
      ROW('netflix.com', ROW(ARRAY[
        MAP(ARRAY['term', 'count'], ARRAY['cartoons', '1020']),
        MAP(ARRAY['term', 'count'], ARRAY['house of cards', '112042']),
        MAP(ARRAY['term', 'count'], ARRAY['orange is the new black', '342']),
        MAP(ARRAY['term', 'count'], ARRAY['iot', '4'])
      ])
      ) AS ROW(hostname VARCHAR, flaggedActivity ROW(flags ARRAY(MAP(VARCHAR, VARCHAR)) ))
    )
  ] AS items
),
sites AS (
  SELECT sites.hostname, sites.flaggedactivity
  FROM dataset, UNNEST(items) t(sites)
)
SELECT hostname, array_agg(flags['term']) AS terms, SUM(CAST(flags['count'] AS INTEGER)) AS total
FROM sites, UNNEST(sites.flaggedActivity.flags) t(flags)
WHERE regexp_like(flags['term'], 'politics|bigdata')
GROUP BY (hostname)
ORDER BY total DESC
```
이 쿼리는 다음 두 사이트를 반환합니다.  

```
+------------------------------------+
| hostname       | terms    | total  |
+----------------+-------------------+
| news.cnn.com   | politics |  241   |
+----------------+-------------------+
| aws.amazon.com | bigdata |  10    |
+----------------+-------------------+
```