

# CSV SerDe 라이브러리
<a name="serde-csv-choices"></a>

Athena에서 CSV 데이터용 테이블을 생성할 때 Open CSV SerDe 또는 Lazy Simple SerDe 라이브러리를 사용할 수 있습니다. 어떤 것을 사용할지 결정하는 데 도움이 되도록 다음 지침을 고려하세요.
+ 데이터에 큰따옴표(`"`)로 묶인 값이 포함되어 있으면 [Open CSV SerDe](https://cwiki.apache.org/confluence/display/Hive/CSV+Serde) 라이브러리를 사용하여 Athena의 값을 역직렬화할 수 있습니다. 데이터에 큰따옴표(`"`)로 묶인 값이 포함되어 있지 않으면 SerDe를 지정하지 않아도 됩니다. 이 경우 Athena는 기본 Lazy Simple SerDe를 사용합니다. 자세한 내용은 [CSV, TSV, 사용자 지정 구분 기호로 구분된 파일에 대한 Lazy Simple SerDe](lazy-simple-serde.md)을 참조하세요.
+  데이터에 UNIX 숫자 `TIMESTAMP` 값이 있는 경우(예: `1579059880000`) Open CSV SerDe를 사용합니다. 데이터가 `java.sql.Timestamp` 형식을 사용하는 경우 Lazy Simple SerDe를 사용합니다.

**Topics**
+ [CSV, TSV, 사용자 지정 구분 기호로 구분된 파일에 대한 Lazy Simple SerDe](lazy-simple-serde.md)
+ [CSV 처리를 위한 Open CSV SerDe](csv-serde.md)

# CSV, TSV, 사용자 지정 구분 기호로 구분된 파일에 대한 Lazy Simple SerDe
<a name="lazy-simple-serde"></a>

이는 Athena에서 CSV, TSV 및 사용자 지정 구분 기호로 구분된 형식의 데이터에 대한 기본 SerDe이므로 이 항목을 지정하는 것은 선택 사항입니다. `CREATE TABLE` 문에서 SerDe를 지정하지 않고 `ROW FORMAT DELIMITED`만 지정하는 경우 Athena는 이 SerDE를 사용합니다. 데이터에 인용 부호로 묶인 값이 없는 경우 이 SerDe를 사용합니다.

Lazy Simple SerDe에 대한 참조 문서는 Apache Hive 개발자 안내서의 [Hive SerDe](https://cwiki.apache.org/confluence/display/Hive/DeveloperGuide#DeveloperGuide-HiveSerDe) 섹션을 참조하세요.

## 직렬화 라이브러리 이름
<a name="lazy-simple-serde-library-name"></a>

Lazy Simple SerDe의 직렬화 라이브러리 이름은 `org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe`입니다. 소스 코드 정보는 GitHub.com의 [LazySimpleSerDe.java](https://github.com/apache/hive/blob/master/serde/src/java/org/apache/hadoop/hive/serde2/lazy/LazySimpleSerDe.java)를 참조하세요.

## 헤더 무시
<a name="lazy-simple-serde-ignoring-headers"></a>

테이블을 정의할 때 데이터의 헤더를 무시하려면 다음 예제와 같이 `skip.header.line.count` 테이블 속성을 사용합니다.

```
TBLPROPERTIES ("skip.header.line.count"="1")
```

헤더를 무시하는 예제는 [Amazon VPC 흐름 로그 쿼리](vpc-flow-logs.md) 및 [Amazon CloudFront 로그 쿼리](cloudfront-logs.md)의 `CREATE TABLE` 문을 참조하세요.

## CSV 예
<a name="csv-example"></a>

다음 예제에서는 Athena에서 `LazySimpleSerDe` 라이브러리를 사용하여 CSV 데이터로 테이블을 생성하는 방법을 보여줍니다. 이 SerDe를 사용하여 사용자 지정 구분 파일을 역직렬화하려면 다음 예제의 패턴을 따라합니다. 단, `FIELDS TERMINATED BY` 절을 사용하여 서로 다른 단일 문자 구분 기호를 지정합니다. Lazy Simple SerDe는 다중 문자 구분 기호를 지원하지 않습니다.

**참고**  
`s3://athena-examples-myregion/path/to/data/`의 *myregion*을, Athena를 실행하는 리전 식별자로 바꿉니다(예: `s3://athena-examples-us-west-1/path/to/data/`).

`CREATE TABLE` 문을 사용하여 Amazon S3에 저장된 CSV 형식의 기본 데이터로 Athena 테이블을 만듭니다.

```
CREATE EXTERNAL TABLE flight_delays_csv (
    yr INT,
    quarter INT,
    month INT,
    dayofmonth INT,
    dayofweek INT,
    flightdate STRING,
    uniquecarrier STRING,
    airlineid INT,
    carrier STRING,
    tailnum STRING,
    flightnum STRING,
    originairportid INT,
    originairportseqid INT,
    origincitymarketid INT,
    origin STRING,
    origincityname STRING,
    originstate STRING,
    originstatefips STRING,
    originstatename STRING,
    originwac INT,
    destairportid INT,
    destairportseqid INT,
    destcitymarketid INT,
    dest STRING,
    destcityname STRING,
    deststate STRING,
    deststatefips STRING,
    deststatename STRING,
    destwac INT,
    crsdeptime STRING,
    deptime STRING,
    depdelay INT,
    depdelayminutes INT,
    depdel15 INT,
    departuredelaygroups INT,
    deptimeblk STRING,
    taxiout INT,
    wheelsoff STRING,
    wheelson STRING,
    taxiin INT,
    crsarrtime INT,
    arrtime STRING,
    arrdelay INT,
    arrdelayminutes INT,
    arrdel15 INT,
    arrivaldelaygroups INT,
    arrtimeblk STRING,
    cancelled INT,
    cancellationcode STRING,
    diverted INT,
    crselapsedtime INT,
    actualelapsedtime INT,
    airtime INT,
    flights INT,
    distance INT,
    distancegroup INT,
    carrierdelay INT,
    weatherdelay INT,
    nasdelay INT,
    securitydelay INT,
    lateaircraftdelay INT,
    firstdeptime STRING,
    totaladdgtime INT,
    longestaddgtime INT,
    divairportlandings INT,
    divreacheddest INT,
    divactualelapsedtime INT,
    divarrdelay INT,
    divdistance INT,
    div1airport STRING,
    div1airportid INT,
    div1airportseqid INT,
    div1wheelson STRING,
    div1totalgtime INT,
    div1longestgtime INT,
    div1wheelsoff STRING,
    div1tailnum STRING,
    div2airport STRING,
    div2airportid INT,
    div2airportseqid INT,
    div2wheelson STRING,
    div2totalgtime INT,
    div2longestgtime INT,
    div2wheelsoff STRING,
    div2tailnum STRING,
    div3airport STRING,
    div3airportid INT,
    div3airportseqid INT,
    div3wheelson STRING,
    div3totalgtime INT,
    div3longestgtime INT,
    div3wheelsoff STRING,
    div3tailnum STRING,
    div4airport STRING,
    div4airportid INT,
    div4airportseqid INT,
    div4wheelson STRING,
    div4totalgtime INT,
    div4longestgtime INT,
    div4wheelsoff STRING,
    div4tailnum STRING,
    div5airport STRING,
    div5airportid INT,
    div5airportseqid INT,
    div5wheelson STRING,
    div5totalgtime INT,
    div5longestgtime INT,
    div5wheelsoff STRING,
    div5tailnum STRING
)
    PARTITIONED BY (year STRING)
    ROW FORMAT DELIMITED
      FIELDS TERMINATED BY ','
      ESCAPED BY '\\'
      LINES TERMINATED BY '\n'
    LOCATION 's3://athena-examples-myregion/flight/csv/';
```

이 테이블에 새 파티션이 추가될 때마다 `MSCK REPAIR TABLE`을(를) 실행하여 파티션 메타데이터를 새로 고칩니다.

```
MSCK REPAIR TABLE flight_delays_csv;
```

1시간 이상 지연된 상위 10개 경로를 쿼리합니다.

```
SELECT origin, dest, count(*) as delays
FROM flight_delays_csv
WHERE depdelayminutes > 60
GROUP BY origin, dest
ORDER BY 3 DESC
LIMIT 10;
```

**참고**  
비행 테이블 데이터의 출처는 미국 운수부 [운송통계국](http://www.transtats.bts.gov/)에서 제공한 [항공편](http://www.transtats.bts.gov/DL_SelectFields.asp?Table_ID=236&amp;DB_Short_Name=On-Time)입니다. 원본에서 채도를 낮췄습니다.

## TSV 예
<a name="tsv-example"></a>

Amazon S3에 저장된 TSV 데이터에서 Athena 테이블을 생성하려면 `ROW FORMAT DELIMITED`를 사용하고 `\t`를 탭 필드 구분 기호로, `\n`을 줄 구분 기호로, `\`를 이스케이프 문자로 지정합니다. 다음 발췌 부분에서 이 구문을 보여줍니다. `athena-examples` 위치에 사용 가능한 샘플 TSV 플라이트 데이터가 없지만 CSV 테이블과 마찬가지로 새 파티션을 추가할 때마다 파티션 메타데이터를 새로 고치도록 `MSCK REPAIR TABLE`을 실행해야 합니다.

```
...
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
ESCAPED BY '\\'
LINES TERMINATED BY '\n'
...
```

# CSV 처리를 위한 Open CSV SerDe
<a name="csv-serde"></a>

Open CSV SerDe 라이브러리를 사용하여 Athena에서 쉼표로 구분된 데이터(CSV)의 테이블을 만듭니다.

## 직렬화 라이브러리 이름
<a name="csv-serde-library-name"></a>

Open CSV SerDe의 직렬화 라이브러리 이름은 `org.apache.hadoop.hive.serde2.OpenCSVSerde`입니다. 소스 코드 정보는 Apache 설명서의 [CSV SerDe](https://cwiki.apache.org/confluence/display/Hive/CSV+Serde)를 참조하세요.

## Open CSV SerDe 사용
<a name="csv-serde-using"></a>

이 SerDe를 사용하려면 `ROW FORMAT SERDE` 뒤에 정규화된 클래스 이름을 지정합니다. 또한 다음 예제와 같이 `SERDEPROPERTIES` 안에 구분 기호를 지정합니다.

```
...
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
  "separatorChar" = ",",
  "quoteChar"     = "`",
  "escapeChar"    = "\\"
)
```

### 헤더 무시
<a name="csv-serde-opencsvserde-ignoring-headers"></a>

테이블을 정의할 때 데이터의 헤더를 무시하려면 다음 예제와 같이 `skip.header.line.count` 테이블 속성을 사용합니다.

```
TBLPROPERTIES ("skip.header.line.count"="1")
```

예제는 [Amazon VPC 흐름 로그 쿼리](vpc-flow-logs.md) 및 [Amazon CloudFront 로그 쿼리](cloudfront-logs.md)의 `CREATE TABLE` 문을 참조하세요.

### 잘못된 데이터에 NULL 사용
<a name="csv-serde-opencsvserde-using-null"></a>

열의 정의된 유형으로 역직렬화되지 않는 데이터에 NULL 값을 사용하려면 다음 예제와 같이 `use.null.for.invalid.data` 테이블 속성을 사용할 수 있습니다.

```
TBLPROPERTIES ("skip.header.line.count"="1")
```

**중요**  
`use.null.for.invalid.data`를 `TRUE`로 설정하면 `NULL` 값이 열의 잘못된 데이터를 스키마 불일치로 대체하기 때문에 잘못되거나 예상치 못한 결과가 발생할 수 있습니다. 이 속성을 활성화하는 대신 파일 또는 테이블 스키마의 데이터를 수정하는 것이 좋습니다. 이 속성을 활성화하면 잘못된 데이터에 대한 쿼리가 실패하지 않으므로 데이터 품질 문제를 발견하지 못할 수 있습니다.

### 문자열 데이터에 대한 고려 사항
<a name="csv-serde-opencsvserde-considerations-string"></a>

Open CSV SerDe는 문자열 데이터에 대해 다음과 같은 특성을 갖습니다.
+ 큰따옴표(`"`)를 기본 인용 부호로 사용하고 다음과 같은 구분자, 따옴표 및 이스케이프 문자를 지정할 수 있습니다.

  ```
  WITH SERDEPROPERTIES ("separatorChar" = ",", "quoteChar" = "`", "escapeChar" = "\\" )
  ```
+ `\t` 또는 `\n`을 직접 이스케이프할 수 없습니다. 이스케이프하려면 `"escapeChar" = "\\"`를 사용합니다. 문제 해결 예는 [Example: Escaping \t or \n](#csv-serde-opencsvserde-example-escaping-t-or-n)을(를) 참조하세요.
+ Open CSV SerDe는 CSV 파일에 포함된 줄 바꿈을 지원하지 않습니다.

### 비문자열 데이터에 대한 고려 사항
<a name="csv-serde-opencsvserde-considerations-non-string"></a>

`STRING`이 아닌 데이터 형식의 경우 Open CSV SerDe는 다음과 같이 동작합니다.
+ `BOOLEAN`, `BIGINT`, `INT`, `DOUBLE` 데이터 형식을 인식합니다.
+ 숫자 데이터 형식으로 정의된 열의 빈 값이나 null 값을 인식하지 못하므로 이러한 값을 `string`으로 유지합니다. 한 가지 해결 방법은 null 값을 포함한 열을 `string`으로 생성한 다음 `CAST`를 사용하여 쿼리의 필드를 숫자 데이터 형식으로 변환하면서 null에 대해 기본값 `0`을 부여하는 것입니다. 자세한 내용은 AWS 지식 센터의 [Athena에서 CSV 데이터를 쿼리하는 경우 HIVE\$1BAD\$1DATA: Error parsing field value 오류가 발생합니다](https://aws.amazon.com/premiumsupport/knowledge-center/athena-hive-bad-data-error-csv/)를 참조하세요.
+ `CREATE TABLE` 문에서 `timestamp` 데이터 형식으로 지정된 열의 경우 밀리초 단위의 UNIX 숫자 형식(예: `1579059880000`)으로 지정되어 있으면 `TIMESTAMP` 데이터를 인식합니다. 문제 해결 예는 [Example: Using the TIMESTAMP type and DATE type specified in the UNIX numeric format](#csv-serde-opencsvserde-example-timestamp-unix)을(를) 참조하세요.
  + Open CSV SerDe는 `"YYYY-MM-DD HH:MM:SS.fffffffff"`(소수점 9자리 정밀도)처럼 JDBC와 호환되는 `java.sql.Timestamp` 형식의 `TIMESTAMP`는 지원하지 않습니다.
+ `CREATE TABLE` 문에서 `DATE` 데이터 형식으로 지정된 열의 경우 값이 1970년 1월 1일 이후 경과된 일 수를 나타내면 값을 인식합니다. 예를 들어 `date` 데이터 형식을 가진 열의 값 `18276`은 쿼리 시 `2020-01-15`로 렌더링됩니다. 이 UNIX 형식에서는 하루를 86,400초로 간주합니다.
  + Open CSV SerDe는 다른 형식의 `DATE`를 직접 지원하지 않습니다. 다른 형식의 타임스탬프 데이터를 처리하려면 열을 `string`으로 정의한 다음 `SELECT` 쿼리에서 원하는 결과를 반환하도록 시간 변환 함수를 사용합니다. 자세한 내용은 [AWS 지식 센터](https://aws.amazon.com/premiumsupport/knowledge-center/)의 [Amazon Athena에서 테이블을 쿼리할 때 TIMESTAMP 결과가 비어 있음](https://aws.amazon.com/premiumsupport/knowledge-center/query-table-athena-timestamp-empty/) 항목을 참조하세요.
+ 표에서 열을 원하는 형식으로 변환하려면 테이블에 대한 [뷰를 생성](views.md)하고 `CAST`를 사용하여 원하는 형식으로 변환할 수 있습니다.

## 예제
<a name="csv-serde-opencsvserde-examples"></a>

**Example 예제: 단순 CSV 데이터 쿼리**  
다음 예제에서는 위치 `s3://amzn-s3-demo-bucket/mycsv/`에 다음과 같은 내용이 포함된 CSV 데이터가 저장되어 있다고 가정합니다.  

```
"a1","a2","a3","a4"
"1","2","abc","def"
"a","a1","abc3","ab4"
```
`CREATE TABLE` 문을 사용해 해당 데이터를 바탕으로 한 Athena 테이블을 만듭니다. 다음 예제처럼 `ROW FORMAT SERDE` 뒤의 `OpenCSVSerde`(‘d’가 소문자임)를 참조해 `WITH SERDEPROPERTIES`에 문자 구분 기호, 따옴표, 이스케이프 문자를 지정합니다.  

```
CREATE EXTERNAL TABLE myopencsvtable (
   col1 string,
   col2 string,
   col3 string,
   col4 string
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
   'separatorChar' = ',',
   'quoteChar' = '"',
   'escapeChar' = '\\'
   )
STORED AS TEXTFILE
LOCATION 's3://amzn-s3-demo-bucket/mycsv/';
```
테이블의 모든 값을 쿼리합니다.  

```
SELECT * FROM myopencsvtable;
```
쿼리는 다음 값을 반환합니다.  

```
col1     col2    col3    col4
-----------------------------
a1       a2      a3      a4
1        2       abc     def
a        a1      abc3    ab4
```

**Example 예: UNIX 숫자 형식으로 지정된 TIMESTAMP 형식 및 DATE 형식 사용**  
쉼표로 구분된 데이터를 포함한 다음 3개 열을 생각해보겠습니다. 각 열의 값은 큰따옴표로 묶여 있습니다.  

```
"unixvalue creationdate 18276 creationdatetime 1579059880000","18276","1579059880000"
```
다음 문은 Athena에서, 지정된 Amazon S3 버킷 위치로부터 테이블을 만듭니다.  

```
CREATE EXTERNAL TABLE IF NOT EXISTS testtimestamp1(
 `profile_id` string,
 `creationdate` date,
 `creationdatetime` timestamp
 )
 ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
 LOCATION 's3://amzn-s3-demo-bucket'
```
이제 다음 쿼리를 실행합니다.  

```
SELECT * FROM testtimestamp1
```
이 쿼리는 날짜 및 시간 데이터를 보여주는 다음과 같은 결과를 반환합니다.  

```
profile_id                                                        creationdate     creationdatetime
unixvalue creationdate 18276 creationdatetime 1579146280000       2020-01-15       2020-01-15 03:44:40.000
```

**Example 예: \$1t 또는 \$1n 이스케이프**  
다음 테스트 데이터를 고려하세요.  

```
" \\t\\t\\n 123 \\t\\t\\n ",abc
" 456 ",xyz
```
다음 문은 Athena에서 `"escapeChar" = "\\"`를 지정한 테이블을 만듭니다.  

```
CREATE EXTERNAL TABLE test1 (
f1 string,
s2 string) 
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' 
WITH SERDEPROPERTIES ("separatorChar" = ",", "escapeChar" = "\\") 
LOCATION 's3://amzn-s3-demo-bucket/dataset/test1/'
```
이제 다음 쿼리를 실행합니다.  

```
SELECT * FROM test1;
```
`\t` 또는 `\n`을 올바르게 이스케이프하여 이 결과를 반환합니다.  

```
f1            s2
\t\t\n 123 \t\t\n            abc
456                          xyz
```