

 Amazon Redshift는 패치 198부터 새 Python UDF 생성을 더 이상 지원하지 않습니다. 기존 Python UDF는 2026년 6월 30일까지 계속 작동합니다. 자세한 내용은 [블로그 게시물](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)을 참조하세요.

# 튜토리얼: Amazon Redshift Spectrum을 사용한 중첩 데이터 쿼리
<a name="tutorial-query-nested-data"></a>

이 자습서는 Redshift Spectrum을 사용하여 중첩된 데이터를 쿼리하는 방법을 보여줍니다. 중첩 데이터는 중첩된 필드를 포함하는 데이터입니다. 중첩 필드는 배열, 구조체 또는 객체와 같은 단일 엔터티로 함께 조인되는 필드입니다.

**Topics**
+ [개요](#tutorial-nested-data-overview)
+ [1단계: 중첩 데이터가 포함된 외부 테이블 만들기](#tutorial-nested-data-create-table)
+ [2단계: SQL 확장을 통한 Amazon S3의 중첩 데이터 쿼리](#tutorial-query-nested-data-sqlextensions)
+ [중첩 데이터 사용 사례](nested-data-use-cases.md)
+ [중첩된 데이터 제한(미리 보기)](nested-data-restrictions.md)
+ [복잡한 중첩 JSON 직렬화](serializing-complex-JSON.md)

## 개요
<a name="tutorial-nested-data-overview"></a>

Amazon Redshift Spectrum은 Parquet, ORC, JSON 및 Ion 파일 형식에서 중첩 데이터에 대한 쿼리를 지원합니다. Redshift Spectrum은 외부 테이블을 사용하여 데이터에 액세스합니다. 복합 데이터 형식인 `struct`, `array` 및 `map`을 사용하는 외부 테이블을 생성할 수 있습니다.

예를 들어 `customers`라는 폴더에 다음과 같은 Amazon S3 데이터가 저장된 데이터 파일이 있다고 가정하겠습니다. 단일 루트 요소는 없지만 이 샘플 데이터의 각 JSON 객체는 테이블의 행을 나타냅니다.

```
{"id": 1,
 "name": {"given": "John", "family": "Smith"},
 "phones": ["123-457789"],
 "orders": [{"shipdate": "2018-03-01T11:59:59.000Z", "price": 100.50},
            {"shipdate": "2018-03-01T09:10:00.000Z", "price": 99.12}]
}
{"id": 2,
 "name": {"given": "Jenny", "family": "Doe"},
 "phones": ["858-8675309", "415-9876543"],
 "orders": []
}
{"id": 3,
 "name": {"given": "Andy", "family": "Jones"},
 "phones": [],
 "orders": [{"shipdate": "2018-03-02T08:02:15.000Z", "price": 13.50}]
}
```

Amazon Redshift Spectrum을 사용하여 파일의 중첩된 데이터를 쿼리할 수 있습니다. 다음은 이 방법으로 Apache Parquet 데이터를 쿼리하는 방법을 나타내는 자습서입니다.

### 사전 조건
<a name="tutorial-nested-data-prereq"></a>

Redshift Spectrum을 아직 사용하지 않고 있다면 계속 진행하기 전에 [Amazon Redshift Spectrum 시작하기](c-getting-started-using-spectrum.md)에서 다음 단계를 따르세요.

외부 스키마를 만들려면 다음 명령에서 IAM 역할 ARN을 [IAM 역할 생성](c-getting-started-using-spectrum.md#c-getting-started-using-spectrum-create-role)에서 생성한 역할 ARN으로 대체합니다. 그런 다음 SQL 클라이언트에서 명령을 실행합니다.

```
create external schema spectrum 
from data catalog 
database 'myspectrum_db' 
iam_role 'arn:aws:iam::123456789012:role/myspectrum_role'
create external database if not exists;
```

## 1단계: 중첩 데이터가 포함된 외부 테이블 만들기
<a name="tutorial-nested-data-create-table"></a>

Amazon S3에서 [소스 데이터](https://s3.amazonaws.com/redshift-downloads/tickit/spectrum/customers/customer_file1)를 다운로드하여 볼 수 있습니다. 

이번 자습서에서 사용할 외부 테이블을 만들려면 다음과 같이 명령을 실행합니다.

```
CREATE EXTERNAL TABLE spectrum.customers (
  id     int,
  name   struct<given:varchar(20), family:varchar(20)>,
  phones array<varchar(20)>,
  orders array<struct<shipdate:timestamp, price:double precision>>
)
STORED AS PARQUET
LOCATION 's3://redshift-downloads/tickit/spectrum/customers/';
```

위의 예에서 외부 테이블 `spectrum.customers`는 데이터 형식으로 `struct`와 `array`를 사용하여 중첩 데이터가 포함된 열을 정의합니다. Amazon Redshift Spectrum은 Parquet, ORC, JSON 및 Ion 파일 형식에서 중첩 데이터에 대한 쿼리를 지원합니다. `STORED AS` 파라미터는 Apache Parquet 파일의 경우 `PARQUET`입니다. `LOCATION` 파라미터는 중첩 데이터 또는 파일이 들어 있는 Amazon S3 폴더를 참조해야 합니다. 자세한 내용은 [CREATE EXTERNAL TABLE](r_CREATE_EXTERNAL_TABLE.md) 섹션을 참조하세요.

`array`와 `struct` 형식은 모든 수준에서 중첩이 가능합니다. 예를 들어 다음 예와 같이 `toparray`라는 이름으로 열을 정의할 수 있습니다.

```
toparray array<struct<nestedarray:
         array<struct<morenestedarray: 
         array<string>>>>>
```

또한 다음 예의 `struct` 열처럼 `x` 형식을 중첩시킬 수도 있습니다.

```
x struct<a: string,
         b: struct<c: integer,
                   d: struct<e: string>
                  >
        >
```

## 2단계: SQL 확장을 통한 Amazon S3의 중첩 데이터 쿼리
<a name="tutorial-query-nested-data-sqlextensions"></a>

Redshift Spectrum은 Amazon Redshift SQL 구문 확장을 통해 복합 형식인 `array`, `map` 및 `struct`에 대한 쿼리를 지원합니다.

### 확장 1: 구조체 열에 대한 액세스
<a name="nested-data-sqlextension1"></a>

필드 이름을 경로로 연결하는 점 표기법을 사용해 `struct` 열에서 데이터를 추출할 수 있습니다. 예를 들어 다음은 고객의 성과 이름을 반환하는 쿼리입니다. 이름은 긴 경로인 `c.name.given`을 통해 액세스하고, 성은 긴 경로인 `c.name.family`을 통해 액세스합니다.

```
SELECT c.id, c.name.given, c.name.family
FROM   spectrum.customers c;
```

위의 쿼리는 다음과 같은 데이터를 반환합니다.

```
id | given | family
---|-------|-------
1  | John  | Smith
2  | Jenny | Doe
3  | Andy  | Jones
(3 rows)
```

`struct`는 어떤 수준에서든지 다른 `struct`의 열이 될 수 있고, 이 열은 또다시 다른 `struct`의 열이 될 수 있습니다. 이렇게 깊게 중첩되는 `struct`의 열에 액세스하는 경로는 계속해서 길어질 수 있습니다. 예를 들어 다음 예에서 `x` 열에 대한 정의를 보십시오.

```
x struct<a: string,
         b: struct<c: integer, 
                      d: struct<e: string>
                  >
        >
```

`e`로 `x.b.d.e`의 데이터에 액세스할 수 있습니다.

### 확장 2: FROM 절의 포괄적 배열
<a name="nested-data-sqlextension2"></a>

`array` 절에서 테이블 이름이 아닌 `map` 열을 지정하여 `array` 열(확장 시 `FROM` 열까지도)의 데이터를 추출할 수 있습니다. 이러한 확장은 기본 쿼리의 `FROM` 절은 물론이고 하위 쿼리의 `FROM` 절에도 적용됩니다.

`array` 요소는 `c.orders[0]`와 같이 위치로 참조할 수 있습니다(미리 보기).

포괄적 `arrays`를 조인과 함께 사용하면 다음 사용 사례에서 설명하겠지만 다양한 유형의 중첩 해제가 가능합니다.

#### 내부 조인을 사용한 중첩 해제
<a name="unnest-inner-joins"></a>

다음은 고객 ID와 주문한 고객의 주문 발송일을 선택하는 쿼리입니다. FROM 절의 SQL 확장인 `c.orders o`는 별칭인 `c`에 따라 달라집니다.

```
SELECT c.id, o.shipdate
FROM   spectrum.customers c, c.orders o
```

주문한 고객 `c`마다 `FROM` 절이 고객 `o`의 각 주문 `c`에 대해 행을 하나씩 반환합니다. 각 행은 고객 행 `c`와 주문 행 `o`가 함께 표시됩니다. 그러면 `SELECT` 절에는 `c.id`와 `o.shipdate`만 유지됩니다. 결과는 다음과 같습니다.

```
id|      shipdate
--|----------------------
1 |2018-03-01  11:59:59
1 |2018-03-01  09:10:00
3 |2018-03-02  08:02:15
(3 rows)
```

별칭 `c`는 고객 필드에 대한 액세스를, 그리고 별칭 `o`는 주문 필드에 대한 액세스를 제공합니다.

시맨틱은 표준 SQL과 비슷합니다. `FROM` 절을 다음 중첩 루프를 실행하는 것으로 생각할 수 있습니다. 이후에는 출력할 필드를 선택하는 `SELECT` 절이 나옵니다.

```
for each customer c in spectrum.customers
  for each order o in c.orders
     output c.id and o.shipdate
```

따라서 주문하지 않은 고객은 결과에서도 표시되지 않습니다.

또한 이것을 `FROM` 테이블과 `JOIN` 배열을 사용해 `customers`을 실행하는 `orders` 절이라고 생각할 수도 있습니다. 실제로 다음 예와 같이 쿼리를 작성하는 것도 가능합니다.

```
SELECT c.id, o.shipdate
FROM   spectrum.customers c INNER JOIN c.orders o ON true
```

**참고**  
이름이 `c`인 테이블에 `orders`라는 스키마가 존재한다면 `c.orders`는 `orders`의 배열 열이 아닌 `customers` 테이블을 참조합니다.

#### 왼쪽 조인을 사용한 중첩 해제
<a name="unnest-left-joins"></a>

다음은 모든 고객 이름과 고객의 주문을 출력하는 쿼리입니다. 따라서 주문하지 않은 고객의 이름까지 모두 반환됩니다. 하지만 이 경우에는 아래 Jenny Doe의 예와 같이 주문 열이 NULL 값을 갖습니다.

```
SELECT c.id, c.name.given, c.name.family, o.shipdate, o.price
FROM   spectrum.customers c LEFT JOIN c.orders o ON true
```

위의 쿼리는 다음과 같은 데이터를 반환합니다.

```
id  |  given  | family  |    shipdate          | price
----|---------|---------|----------------------|--------
 1  |  John   | Smith   | 2018-03-01  11:59:59 | 100.5
 1  |  John   | Smith   | 2018-03-01  09:10:00 |  99.12
 2  |  Jenny  | Doe     |                      |
 3  |  Andy   | Jones   | 2018-03-02  08:02:15 |  13.5
 (4 rows)
```

### 확장 3: 별칭을 사용해 스칼라 배열에 직접 액세스
<a name="nested-data-sqlextension3"></a>

`FROM` 절의 별칭 `p`가 스칼라 배열을 포괄하는 경우에는 쿼리가 `p` 값을 `p`로 참조합니다. 예를 들어 다음은 고객 이름과 전화 번호를 쌍으로 반환하는 쿼리입니다.

```
SELECT c.name.given, c.name.family, p AS phone
FROM   spectrum.customers c LEFT JOIN c.phones p ON true
```

위의 쿼리는 다음과 같은 데이터를 반환합니다.

```
given  |  family  |  phone
-------|----------|-----------
John   | Smith    | 123-4577891
Jenny  | Doe      | 858-8675309
Jenny  | Doe      | 415-9876543
Andy   | Jones    | 
(4 rows)
```

### 확장 4: 맵 요소에 대한 액세스
<a name="nested-data-sqlextension4"></a>

Redshift Spectrum은 `map` 데이터 형식을 `array` 열과 `struct` 열로 구성된 `key` 형식이 포함된 `value` 형식으로 처리합니다. `key`는 `scalar`가 되어야 하고, 값은 어떤 데이터 형식이든 될 수 있습니다.

예를 들어 다음은 전화 번호를 저장할 목적으로 `map`이 포함된 외부 테이블을 만드는 코드입니다.

```
CREATE EXTERNAL TABLE spectrum.customers2 (
  id     int,
  name   struct<given:varchar(20), family:varchar(20)>,
  phones map<varchar(20), varchar(20)>,
  orders array<struct<shipdate:timestamp, price:double precision>>
)
STORED AS PARQUET
LOCATION 's3://redshift-downloads/tickit/spectrum/customers/';
```

`map` 형식은 `array` 열과 `key` 열로 구성된 `value` 형식처럼 처리되기 때문에 앞에 나오는 스키마를 마치 뒤에 나오는 스키마라고 생각할 수 있습니다.

```
CREATE EXTERNAL TABLE spectrum.customers3 (
  id     int,
  name   struct<given:varchar(20), family:varchar(20)>,
  phones array<struct<key:varchar(20), value:varchar(20)>>,
  orders array<struct<shipdate:timestamp, price:double precision>>
)
STORED AS PARQUET
LOCATION 's3://redshift-downloads/tickit/spectrum/customers/';
```

다음은 고객 이름과 휴대 전화 번호를 함께 반환한 후 각 이름의 번호를 반환하는 쿼리입니다. 맵 쿼리는 `array` 형식의 중첩 `struct`를 쿼리하는 것과 동일하게 처리됩니다. 다음은 앞에서 설명한 외부 테이블을 만든 경우에만 데이터를 반환하는 쿼리입니다.

```
SELECT c.name.given, c.name.family, p.value 
FROM   spectrum.customers c, c.phones p 
WHERE  p.key = 'mobile';
```

**참고**  
`key`에 대한 `map`는 Ion 및 JSON 파일 형식에 대한 `string`입니다.

# 중첩 데이터 사용 사례
<a name="nested-data-use-cases"></a>

이 주제에서는 중첩된 데이터의 사용 사례를 설명합니다. 중첩 데이터는 중첩된 필드를 포함하는 데이터입니다. 중첩 필드는 배열, 구조체 또는 객체와 같은 단일 엔터티로 함께 조인되는 필드입니다.

앞에서 설명한 확장을 일반적인 SQL 기능과 결합할 수 있습니다. 다음 사용 사례는 일반적인 몇 가지 결합에 대한 설명입니다. 각 사례는 중첩 데이터의 사용 방법을 이해하는 데 도움이 될 것입니다. 자습서에는 포함되어 있지 않습니다.

**Topics**
+ [중첩 데이터 수집](#ingesting-nested-data)
+ [하위 쿼리를 사용한 중첩 데이터 집계](#aggregating-with-subquery)
+ [Amazon Redshift 및 중첩 데이터 조인](#joining-redshift-data)

## 중첩 데이터 수집
<a name="ingesting-nested-data"></a>

`CREATE TABLE AS` 문을 사용하여 복합 데이터 형식이 포함된 외부 테이블에서 데이터를 수집할 수 있습니다. 다음은 `LEFT JOIN`을 사용해 외부 테이블의 고객과 고객 전화 번호를 모두 추출한 후 Amazon Redshift 테이블인 `CustomerPhones`에 저장하는 쿼리입니다.

```
CREATE TABLE CustomerPhones AS
SELECT  c.name.given, c.name.family, p AS phone
FROM    spectrum.customers c LEFT JOIN c.phones p ON true;
```

## 하위 쿼리를 사용한 중첩 데이터 집계
<a name="aggregating-with-subquery"></a>

하위 쿼리를 사용해 중첩 데이터를 집계할 수 있습니다. 다음은 이러한 방법을 설명하는 예입니다.

```
SELECT c.name.given, c.name.family, (SELECT COUNT(*) FROM c.orders o) AS ordercount 
FROM   spectrum.customers c;
```

다음 데이터가 반환됩니다.

```
given   |  family  |  ordercount
--------|----------|--------------
 Jenny  |  Doe     |       0
 John   |  Smith   |       2
 Andy   |  Jones   |       1
 (3 rows)
```

**참고**  
상위 행을 기준으로 그룹화하여 중첩 데이터를 집계할 때는 이전 예와 같은 방법이 가장 효율적입니다. 위의 예에서 중첩 행인 `c.orders`는 상위 행인 `c`를 기준으로 그룹화됩니다. 또는 `id`가 각 `customer`마다 고유하고, `o.shipdate`는 절대 NULL 값이 아니라는 사실을 알고 있다면 다음 예와 같이 집계하는 방법도 있습니다. 하지만 이 방법은 일반적으로 이전 예만큼 효율적이지 않습니다.

```
SELECT    c.name.given, c.name.family, COUNT(o.shipdate) AS ordercount 
FROM      spectrum.customers c LEFT JOIN c.orders o ON true 
GROUP BY  c.id, c.name.given, c.name.family;
```

또는 `FROM` 절에서 최상위 쿼리의 별칭(`c`)을 참조하여 배열 데이터를 추출하는 하위 쿼리를 사용하여 쿼리를 작성할 수도 있습니다. 다음 예에서는 이 방법을 보여 줍니다.

```
SELECT c.name.given, c.name.family, s.count AS ordercount
FROM   spectrum.customers c, (SELECT count(*) AS count FROM c.orders o) s;
```

## Amazon Redshift 및 중첩 데이터 조인
<a name="joining-redshift-data"></a>

Amazon Redshift 데이터를 외부 테이블의 중첩 데이터와 조인시킬 수 있습니다. 예를 들어 Amazon S3에 다음과 같은 중첩 데이터가 있다고 가정하겠습니다.

```
CREATE EXTERNAL TABLE spectrum.customers2 (
  id      int,
  name    struct<given:varchar(20), family:varchar(20)>,
  phones  array<varchar(20)>,
  orders  array<struct<shipdate:timestamp, item:int>>
);
```

또한 Amazon Redshift에 다음과 같은 테이블이 있다고 가정하겠습니다.

```
CREATE TABLE prices (
  id int,
  price double precision
);
```

다음은 앞의 예를 근거로 각 고객이 구매한 총 상품 수와 양을 요청하는 쿼리입니다. 다음은 이해를 돕기 위한 예입니다. 앞에서 설명한 테이블을 만든 경우에만 데이터를 반환합니다.

```
SELECT   c.name.given, c.name.family, COUNT(o.date) AS ordercount, SUM(p.price) AS ordersum 
FROM     spectrum.customers2 c, c.orders o, prices p ON o.item = p.id  
GROUP BY c.id, c.name.given, c.name.family;
```

# 중첩된 데이터 제한(미리 보기)
<a name="nested-data-restrictions"></a>

이 주제에서는 Redshift Spectrum을 사용하여 중첩된 데이터를 읽을 때의 제한 사항에 대해 설명합니다. 중첩 데이터는 중첩된 필드를 포함하는 데이터입니다. 중첩 필드는 배열, 구조체 또는 객체와 같은 단일 엔터티로 함께 조인되는 필드입니다.

**참고**  
다음 목록에서 (미리 보기)로 표시된 제한 사항은 다음 리전에서 생성된 미리 보기 클러스터에만 적용됩니다.  
미국 동부(오하이오)(us-east-2)
미국 동부(버지니아 북부)(us-east-1)
미국 서부(캘리포니아 북부)(us-west-1)
아시아 태평양(도쿄)(ap-northeast-1)
유럽(아일랜드)(eu-west-1)
유럽(스톡홀름)(eu-north-1)
미리 보기 클러스터 설정에 대한 내용은 **Amazon Redshift 클러스터 관리 안내서의 [미리 보기 클러스터 생성](https://docs.aws.amazon.com/redshift/latest/mgmt/managing-clusters-console.html#cluster-preview)을 참조하세요.

중첩 데이터에는 다음과 같은 제약이 적용됩니다.
+ `array` 또는 `map` 유형에는 쿼리가 중첩된 `arrays`에 있거나 `maps`가 `scalar` 값을 반환하지 않는 한 다른 `array` 또는 `map` 유형이 포함될 수 있습니다. (미리 보기) 
+ Amazon Redshift Spectrum은 외부 테이블의 형태로만 복합 데이터 유형을 지원합니다.
+  하위 쿼리 결과 열은 최상위 수준이어야 합니다. (미리 보기)
+ `OUTER JOIN` 표현식이 중첩 테이블을 참조하는 경우에는 해당 테이블과 테이블의 중첩 배열(및 맵)만 참조할 수 있습니다. `OUTER JOIN` 표현식이 중첩 테이블을 참조하지 않는 경우에는 비중첩 테이블을 무제한 참조할 수 있습니다.
+ 하위 쿼리의 `FROM` 절이 중첩 테이블을 참조하는 경우에는 다른 테이블을 참조할 수 없습니다.
+ 하위 쿼리가 상위 테이블을 참조하는 중첩 테이블에 따라 달라지는 경우, 하위 쿼리는 `FROM` 절에서 상위 테이블만 사용할 수 있습니다. `SELECT` 또는 `WHERE` 절 같은 다른 절에서는 상위 쿼리를 사용할 수 없습니다. 예를 들어 다음 쿼리는 하위 쿼리의 `SELECT` 절이 상위 테이블 `c`를 참조하므로 실행되지 않습니다.

  ```
  SELECT c.name.given 
  FROM   spectrum.customers c 
  WHERE (SELECT COUNT(c.id) FROM c.phones p WHERE p LIKE '858%') > 1;
  ```

  다음 쿼리는 상위 쿼리의 `c`가 하위 쿼리의 `FROM` 절에서만 사용되고 있기 때문에 유효합니다.

  ```
  SELECT c.name.given 
  FROM   spectrum.customers c 
  WHERE (SELECT COUNT(*) FROM c.phones p WHERE p LIKE '858%') > 1;
  ```
+ `FROM` 절이 아닌 다른 곳의 중첩 데이터에 액세스하는 하위 쿼리는 단일 값을 반환해야 합니다. `(NOT) EXISTS` 절의 `WHERE` 연산자만 예외입니다.
+ `(NOT) IN`는 지원되지 않습니다.
+ 모든 중첩 형식의 최대 중첩 깊이는 100입니다. 이러한 제약은 모든 파일 형식(Parquet, ORC, Ion, JSON)에 적용됩니다.
+ 중첩 데이터에 액세스하는 집계 하위 쿼리는 `arrays`의 `maps` 및 `FROM`만 참조할 수 있고 외부 테이블은 참조할 수 없습니다.
+ Redshift 스펙트럼 테이블에서 중첩된 데이터의 가성 열을 쿼리하는 것은 지원되지 않습니다. 자세한 내용은 [가상 열](c-spectrum-external-tables.md#c-spectrum-external-tables-pseudocolumns) 섹션을 참조하세요.
+ 배열이나 맵 열을 `FROM` 절에 지정하여 배열이나 맵에서 데이터를 추출하는 경우 값이 `scalar`인 경우에만 해당 열에서 값을 선택할 수 있습니다. 예를 들어, 다음 쿼리는 모두 배열 내부의 요소에서 `SELECT` 작업 수행을 시도합니다. `arr.a`가 `scalar` 값이기 때문에 `arr.a`를 선택하는 쿼리가 작동합니다. 두 번째 쿼리는 `array`가 `FROM` 절의 `s3.nested table`에서 추출된 배열이기 때문에 작동하지 않습니다. (미리 보기)

  ```
  SELECT array_column FROM s3.nested_table;
  
  array_column
  -----------------
  [{"a":1},{"b":2}]
                          
  SELECT arr.a FROM s3.nested_table t, t.array_column arr;
  
  arr.a
  -----
  1
  
  --This query fails to run.
  SELECT array FROM s3.nested_table tab, tab.array_column array;
  ```

  다른 배열이나 맵에서 가져온 `FROM` 절에 있는 배열이나 맵은 사용할 수 없습니다. 다른 배열 내에 중첩된 배열 또는 기타 복합 구조를 선택하려면 `SELECT` 문에 인덱스를 사용하는 것이 좋습니다.

# 복잡한 중첩 JSON 직렬화
<a name="serializing-complex-JSON"></a>

이 주제에서는 중첩된 데이터를 JSON 형식으로 직렬화하는 방법을 보여줍니다. 중첩 데이터는 중첩된 필드를 포함하는 데이터입니다. 중첩 필드는 배열, 구조체 또는 객체와 같은 단일 엔터티로 함께 조인되는 필드입니다.

이 튜토리얼에서 설명하는 방법의 대안으로 최상위 중첩 컬렉션 열을 직렬화된 JSON으로 쿼리할 수 있습니다. 직렬화를 사용하여 Redshift Spectrum에서 중첩 데이터를 JSON으로 검사, 변환 및 수집할 수 있습니다. 이 방법은 ORC, JSON, Ion 및 Parquet 형식에 대해 지원됩니다. 세션 구성 파라미터 `json_serialization_enable`을 사용하여 직렬화 동작을 구성합니다. 설정하면 복잡한 JSON 데이터 형식이 VARCHAR(65535)로 직렬화됩니다. 중첩 JSON은 [JSON 함수](json-functions.md)로 액세스할 수 있습니다. 자세한 내용은 [json\$1serialization\$1enable](r_json_serialization_enable.md) 섹션을 참조하세요.

예를 들어 `json_serialization_enable`을 설정하지 않으면 중첩 열에 직접 액세스하는 다음 쿼리가 실패합니다.

```
SELECT * FROM spectrum.customers LIMIT 1;

=> ERROR:  Nested tables do not support '*' in the SELECT clause.

SELECT name FROM spectrum.customers LIMIT 1;

=> ERROR:  column "name" does not exist in customers
```

`json_serialization_enable`을 설정하면 최상위 컬렉션을 직접 쿼리할 수 있습니다.

```
SET json_serialization_enable TO true;

SELECT * FROM spectrum.customers order by id LIMIT 1;

id | name                                 | phones         | orders
---+--------------------------------------+----------------+----------------------------------------------------------------------------------------------------------------------
1  | {"given": "John", "family": "Smith"} | ["123-457789"] | [{"shipdate": "2018-03-01T11:59:59.000Z", "price": 100.50}, {"shipdate": "2018-03-01T09:10:00.000Z", "price": 99.12}]          
 
SELECT name FROM spectrum.customers order by id LIMIT 1;

name
---------
{"given": "John", "family": "Smith"}
```

중첩 JSON을 직렬화할 때 다음 항목을 고려합니다.
+ 컬렉션 열이 VARCHAR(65535)로 직렬화되면 쿼리 구문의 일부로(예: 필터 절에서) 중첩 하위 필드에 직접 액세스할 수 없습니다. 그러나 JSON 함수를 사용하여 중첩 JSON에 액세스할 수 있습니다.
+ 다음과 같은 특수 표현은 지원되지 않습니다.
  + ORC 조합
  + 복합 형식 키가 있는 ORC 맵
  + Ion 데이터그램
  + Ion SEXP
+ 타임스탬프는 ISO 직렬화 문자열로 반환됩니다.
+ 기본 맵 키는 문자열로 승격됩니다(예: `1`에서 `"1"`로).
+ 최상위 null 값은 NULL로 직렬화됩니다.
+ 직렬화가 최대 VARCHAR 크기인 65535를 넘으면 셀이 NULL로 설정됩니다.

## JSON 문자열을 포함하는 복합 형식 직렬화
<a name="serializing-complex-JSON-strings"></a>

기본적으로 중첩 컬렉션에 포함된 문자열 값은 이스케이프 처리된 JSON 문자열로 직렬화됩니다. 문자열이 유효한 JSON인 경우 이스케이프가 바람직하지 않을 수 있습니다. 대신 JSON으로 직접 VARCHAR인 중첩 하위 요소 또는 필드를 작성할 수 있습니다. `json_serialization_parse_nested_strings` 세션 수준 구성으로 이 동작을 사용합니다. `json_serialization_enable`과 `json_serialization_parse_nested_strings`가 모두 설정되면 유효한 JSON 값이 이스케이프 문자 없이 인라인으로 직렬화됩니다. 값이 유효한 JSON이 아닌 경우 `json_serialization_parse_nested_strings` 구성 값이 설정되지 않은 것처럼 이스케이프 처리됩니다. 자세한 내용은 [json\$1serialization\$1parse\$1nested\$1strings](r_json_serialization_parse_nested_strings.md) 섹션을 참조하세요.

예를 들어 이전 예의 데이터에서 `name` VARCHAR(20) 필드에 `structs` 복합 형식으로 JSON이 포함되어 있다고 가정합니다.

```
name
---------
{"given": "{\"first\":\"John\",\"middle\":\"James\"}", "family": "Smith"}
```

`json_serialization_parse_nested_strings`가 설정되면 `name` 열은 다음과 같이 직렬화됩니다.

```
SET json_serialization_enable TO true;
SET json_serialization_parse_nested_strings TO true;
SELECT name FROM spectrum.customers order by id LIMIT 1;

name
---------
{"given": {"first":"John","middle":"James"}, "family": "Smith"}
```

다음과 같이 이스케이프 처리되는 대신

```
SET json_serialization_enable TO true;
SELECT name FROM spectrum.customers order by id LIMIT 1;

name
---------
{"given": "{\"first\":\"John\",\"middle\":\"James\"}", "family": "Smith"}
```