

# DynamoDB용 PartiQL 시작하기
<a name="ql-gettingstarted"></a>

이 단원에서는 Amazon DynamoDB 콘솔, AWS Command Line Interface(AWS CLI) 및 DynamoDB API에서 DynamoDB용 PartiQL을 사용하는 방법을 설명합니다.

다음 예에서 [DynamoDB 시작하기](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html) 자습서에 정의된 DynamoDB 테이블은 사전 조건입니다.

DynamoDB 콘솔, AWS Command Line Interface 또는 DynamoDB API를 사용하여 DynamoDB에 액세스하는 방법에 대한 자세한 내용은 [DynamoDB DB 액세스](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html)를 참조하세요.

[NoSQL 워크벤치](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.html)를 [다운로드](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html)하고 사용하여 [DynamoDB용 PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html) 문을 빌드하려면 DynamoDB용 NoSQL Workbench **작업 빌더(Operation Builder)** 오른쪽 맨 위에서 [PartiQL 작업(PartiQL operations)](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.querybuilder.operationbuilder.html)를 선택합니다.

------
#### [ Console ]

![\[Music 테이블에 대한 Query 작업 실행 결과를 보여주는 PartiQL 에디터 인터페이스.\]](http://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/images/partiqlgettingstarted.png)


1. AWS Management Console에 로그인하고 [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)에서 DynamoDB 콘솔을 엽니다.

1. 콘솔 왼쪽의 탐색 창에서 **PartiQL editor(PartiQL 편집기)**를 선택합니다.

1. **Music** 테이블을 선택합니다.

1. **Query table(테이블 쿼리)**을 선택합니다. 이 작업을 수행하면 전체 테이블이 스캔되지 않는 쿼리가 생성됩니다.

1. `partitionKeyValue`를 문자열 값 `Acme Band`로 바꿉니다. `sortKeyValue`를 문자열 값 `Happy Day`로 바꿉니다.

1. **실행** 버튼을 선택합니다.

1. **Table view(테이블 보기)** 또는 **JSON view(JSON 보기)** 버튼을 선택하여 쿼리의 결과를 볼 수 있습니다.

------
#### [ NoSQL workbench ]

![\[NoSQL Workbench 인터페이스. Music 테이블에 대해 실행할 수 있는 PartiQL SELECT 문을 보여줍니다.\]](http://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/images/workbench/partiql.single.png)


1. **PartiQL statement(PartiQL 문)**를 선택합니다.

1. 다음 PartiQL [SELECT 문](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html)을 입력합니다.

   ```
   SELECT *                                         
   FROM Music  
   WHERE Artist=? and SongTitle=?
   ```

1. `Artist` 및 `SongTitle` 파라미터의 값을 지정하려면 다음을 수행합니다.

   1. **Optional request parameters(선택적 요청 파라미터)**를 선택합니다.

   1. **Add new parameter(새 파라미터 추가)**를 선택합니다.

   1. 속성 형식 **문자열**과 값 `Acme Band`를 선택합니다.

   1. b단계와 c단계를 반복하고 형식 **문자열**과 값 `PartiQL Rocks`를 선택합니다.

1. 코드를 생성하려면 **Generate code(코드 생성)**를 선택합니다.

   표시된 탭에서 원하는 언어를 선택합니다. 이제 이 코드를 복사하여 애플리케이션에서 사용할 수 있습니다.

1. 작업을 즉시 실행하려면 **Run(실행)**을 선택합니다.

------
#### [ AWS CLI ]

1. INSERT PartiQL 문을 사용하여 `Music` 테이블에 항목을 생성합니다.

   ```
   aws dynamodb execute-statement --statement "INSERT INTO Music  \
   					    VALUE  \
   					    {'Artist':'Acme Band','SongTitle':'PartiQL Rocks'}"
   ```

1. SELECT PartiQL 문을 사용하여 Music 테이블에서 항목을 검색합니다.

   ```
   aws dynamodb execute-statement --statement "SELECT * FROM Music   \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

1. UPDATE PartiQL 문을 사용하여 `Music` 테이블의 항목을 업데이트합니다.

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardsWon=1  \
                                               SET AwardDetail={'Grammys':[2020, 2018]}  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   `Music` 테이블에서 항목의 목록 값을 추가합니다.

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   `Music` 테이블에서 항목의 목록 값을 제거합니다.

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               REMOVE AwardDetail.Grammys[2]  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   `Music` 테이블에서 항목의 새 맵 멤버를 추가합니다.

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardDetail.BillBoard=[2020]  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   `Music` 테이블에서 항목의 새 문자열 집합 속성을 추가합니다.

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET BandMembers =<<'member1', 'member2'>>  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   `Music` 테이블에서 항목의 문자열 집합 속성을 업데이트합니다.

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET BandMembers =set_add(BandMembers, <<'newmember'>>)  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

1. DELETE PartiQL 문을 사용하여 `Music` 테이블에서 항목을 삭제합니다.

   ```
   aws dynamodb execute-statement --statement "DELETE  FROM Music  \
       WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

------
#### [ Java ]

```
import java.util.ArrayList;
import java.util.List;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import software.amazon.dynamodb.AmazonDynamoDB;
import software.amazon.dynamodb.AmazonDynamoDBClientBuilder;
import software.amazon.dynamodb.model.AttributeValue;
import software.amazon.dynamodb.model.ConditionalCheckFailedException;
import software.amazon.dynamodb.model.ExecuteStatementRequest;
import software.amazon.dynamodb.model.ExecuteStatementResult;
import software.amazon.dynamodb.model.InternalServerErrorException;
import software.amazon.dynamodb.model.ItemCollectionSizeLimitExceededException;
import software.amazon.dynamodb.model.ProvisionedThroughputExceededException;
import software.amazon.dynamodb.model.RequestLimitExceededException;
import software.amazon.dynamodb.model.ResourceNotFoundException;
import software.amazon.dynamodb.model.TransactionConflictException;

public class DynamoDBPartiQGettingStarted {

    public static void main(String[] args) {
        // Create the DynamoDB Client with the region you want
        AmazonDynamoDB dynamoDB = createDynamoDbClient("us-west-1");

        try {
            // Create ExecuteStatementRequest
            ExecuteStatementRequest executeStatementRequest = new ExecuteStatementRequest();
            List<AttributeValue> parameters= getPartiQLParameters();

            //Create an item in the Music table using the INSERT PartiQL statement
            processResults(executeStatementRequest(dynamoDB, "INSERT INTO Music value {'Artist':?,'SongTitle':?}", parameters));

            //Retrieve an item from the Music table using the SELECT PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "SELECT * FROM Music  where Artist=? and SongTitle=?", parameters));

            //Update an item in the Music table using the UPDATE PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET AwardsWon=1 SET AwardDetail={'Grammys':[2020, 2018]}  where Artist=? and SongTitle=?", parameters));

            //Add a list value for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  where Artist=? and SongTitle=?", parameters));

            //Remove a list value for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music REMOVE AwardDetail.Grammys[2]   where Artist=? and SongTitle=?", parameters));

            //Add a new map member for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music set AwardDetail.BillBoard=[2020] where Artist=? and SongTitle=?", parameters));

            //Add a new string set attribute for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET BandMembers =<<'member1', 'member2'>> where Artist=? and SongTitle=?", parameters));

            //update a string set attribute for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET BandMembers =set_add(BandMembers, <<'newmember'>>) where Artist=? and SongTitle=?", parameters));

            //Retrieve an item from the Music table using the SELECT PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "SELECT * FROM Music  where Artist=? and SongTitle=?", parameters));

            //delete an item from the Music Table
            processResults(executeStatementRequest(dynamoDB, "DELETE  FROM Music  where Artist=? and SongTitle=?", parameters));
        } catch (Exception e) {
            handleExecuteStatementErrors(e);
        }
    }

    private static AmazonDynamoDB createDynamoDbClient(String region) {
        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static List<AttributeValue> getPartiQLParameters() {
        List<AttributeValue> parameters = new ArrayList<AttributeValue>();
        parameters.add(new AttributeValue("Acme Band"));
        parameters.add(new AttributeValue("PartiQL Rocks"));
        return parameters;
    }

    private static ExecuteStatementResult executeStatementRequest(AmazonDynamoDB client, String statement, List<AttributeValue> parameters ) {
        ExecuteStatementRequest request = new ExecuteStatementRequest();
        request.setStatement(statement);
        request.setParameters(parameters);
        return client.executeStatement(request);
    }

    private static void processResults(ExecuteStatementResult executeStatementResult) {
        System.out.println("ExecuteStatement successful: "+ executeStatementResult.toString());

    }

    // Handles errors during ExecuteStatement execution. Use recommendations in error messages below to add error handling specific to
    // your application use-case.
    private static void handleExecuteStatementErrors(Exception exception) {
        try {
            throw exception;
        } catch (ConditionalCheckFailedException ccfe) {
            System.out.println("Condition check specified in the operation failed, review and update the condition " +
                                       "check before retrying. Error: " + ccfe.getErrorMessage());
        } catch (TransactionConflictException tce) {
            System.out.println("Operation was rejected because there is an ongoing transaction for the item, generally " +
                                       "safe to retry with exponential back-off. Error: " + tce.getErrorMessage());
        } catch (ItemCollectionSizeLimitExceededException icslee) {
            System.out.println("An item collection is too large, you\'re using Local Secondary Index and exceeded " +
                                       "size limit of items per partition key. Consider using Global Secondary Index instead. Error: " + icslee.getErrorMessage());
        } catch (Exception e) {
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " +
                                       "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                                       "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " +
                                       ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " +
                                       "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                                       "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                                       "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                                       "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

## 파라미터화된 문 사용
<a name="ql-gettingstarted.parameterized"></a>

PartiQL 문 문자열에 직접 값을 포함하는 대신 물음표(`?`) 자리 표시자를 사용하고 `Parameters` 필드에 값을 별도로 제공할 수 있습니다. 각 `?` 값은 제공된 순서대로 해당 파라미터 값으로 대체됩니다.

파라미터화된 문을 사용하는 것이 모범 사례입니다. 문 구조를 데이터 값과 분리하므로 문을 더 쉽게 읽고 재사용할 수 있기 때문입니다. 또한 명령문 문자열에서 속성 값을 수동으로 포맷하고 이스케이프할 필요가 없습니다.

파라미터화된 문은 `ExecuteStatement`, `BatchExecuteStatement` 및 `ExecuteTransaction` 작업에서 지원됩니다.

다음 예제에서는 파티션 키 및 정렬 키에 대해 파라미터화된 값을 사용하여 `Music` 테이블에서 항목을 검색합니다.

------
#### [ AWS CLI parameterized ]

```
aws dynamodb execute-statement \
    --statement "SELECT * FROM \"Music\" WHERE Artist=? AND SongTitle=?" \
    --parameters '[{"S": "Acme Band"}, {"S": "PartiQL Rocks"}]'
```

------
#### [ Java parameterized ]

```
List<AttributeValue> parameters = new ArrayList<>();
parameters.add(new AttributeValue("Acme Band"));
parameters.add(new AttributeValue("PartiQL Rocks"));

ExecuteStatementRequest request = new ExecuteStatementRequest()
    .withStatement("SELECT * FROM Music WHERE Artist=? AND SongTitle=?")
    .withParameters(parameters);

ExecuteStatementResult result = dynamoDB.executeStatement(request);
```

------
#### [ Python parameterized ]

```
response = dynamodb_client.execute_statement(
    Statement="SELECT * FROM Music WHERE Artist=? AND SongTitle=?",
    Parameters=[
        {'S': 'Acme Band'},
        {'S': 'PartiQL Rocks'}
    ]
)
```

------

**참고**  
이전 시작하기 섹션의 Java 예제에서는 파라미터화된 문을 전체적으로 사용합니다. `getPartiQLParameters()` 메서드는 파라미터 목록을 빌드하고 각 문은 인라인 값 대신 `?` 자리 표시자를 사용합니다.