JSON 형식의 Amazon RDS Data API 쿼리 결과 처리
ExecuteStatement
작업을 호출할 때 쿼리 결과를 JSON 형식의 문자열로 반환하도록 선택할 수 있습니다. 이렇게 하면 프로그래밍 언어의 JSON 구문 분석 기능을 사용하여 결과 집합을 해석하고 형식을 다시 지정할 수 있습니다. 그러면 결과 집합을 반복하고 각 열 값을 해석하는 추가 코드를 작성하지 않아도 됩니다.
결과 집합을 JSON 형식으로 요청하려면 선택적으로 formatRecordsAs
파라미터를 JSON
값과 함께 전달합니다. JSON 형식의 결과 집합이 ExecuteStatementResponse
구조의 formattedRecords
필드에 반환됩니다.
BatchExecuteStatement
작업은 결과 집합을 반환하지 않습니다. 따라서 JSON 옵션은 해당 작업에 적용되지 않습니다.
JSON 해시 구조에서 키를 사용자 정의하려면 결과 집합에서 열 별칭을 정의합니다. SQL 쿼리의 열 목록에 있는 AS
절을 사용하면 됩니다.
JSON 기능을 사용하여 결과 집합을 더 쉽게 읽도록 하고 내용을 언어별 프레임워크에 매핑할 수 있습니다. ASCII로 인코딩된 결과 집합의 볼륨이 기본 표현보다 크기 때문에 많은 수의 행이나 큰 열 값을 반환하여 애플리케이션에서 사용할 수 있는 것보다 많은 메모리를 사용하는 쿼리에 기본 표현을 선택할 수 있습니다.
JSON 형식의 쿼리 결과 검색
결과 집합을 JSON 문자열로 수신하려면 ExecuteStatement
호출에 .withFormatRecordsAs(RecordsFormatType.JSON)
을 포함하세요. 반환 값은 formattedRecords
필드에 JSON 문자열로 반환됩니다. 이 경우 columnMetadata
는 null
입니다. 열 레이블은 각 행을 나타내는 객체의 키입니다. 이 열 이름은 결과 집합의 각 행에서 반복됩니다. 열 값은 따옴표로 묶인 문자열, 숫자 값 또는 true
, false
또는 null
을 나타내는 특수 값입니다. 길이 제약 조건 및 숫자 및 문자열의 정확한 유형과 같은 열 메타데이터는 JSON 응답에 보존되지 않습니다.
.withFormatRecordsAs()
호출을 생략하거나 NONE
의 파라미터를 지정하는 경우 결과 집합은 Records
및 columnMetadata
필드를 사용하여 이진 형식으로 반환됩니다.
데이터 유형 매핑
결과 집합의 SQL 값은 더 작은 JSON 유형 집합에 매핑됩니다. 값은 JSON에서 문자열, 숫자 및 true
, false
및 null
과 같은 특수 상수로 표시됩니다. 프로그래밍 언어에 적합하도록 강한 타이핑 또는 약한 타이핑을 사용하여 이 값을 애플리케이션에서 변수로 변환할 수 있습니다.
JDBC 데이터 유형 |
JSON 데이터 유형 |
---|---|
|
기본적으로 숫자입니다. |
|
숫자 |
|
기본적으로 문자열입니다. |
|
문자열 |
|
부울 |
|
base64 인코딩의 문자열입니다. |
|
String |
|
Array |
|
|
다른 형식(날짜 및 시간과 관련된 형식 포함) |
String |
문제 해결
JSON 응답은 10MB로 제한됩니다. 응답이 이 한도보다 크면 프로그램에서 BadRequestException
오류를 받습니다. 이런 경우 다음 기법 중 하나를 사용하여 오류를 해결할 수 있습니다.
-
결과 집합에서 행의 수를 줄입니다.
LIMIT
절을 추가하면 됩니다.LIMIT
및OFFSET
절이 있는 여러 쿼리를 제출하여 큰 결과 집합을 여러 개의 작은 결과 집합으로 나눌 수 있습니다.결과 집합에 애플리케이션 로직별로 필터링된 행이 포함되어 있는 경우
WHERE
절에 조건을 더 추가하여 결과 집합에서 해당 행을 제거할 수 있습니다. -
결과 집합에서 열의 수를 줄입니다. 쿼리의 선택 목록에서 항목을 제거하면 됩니다.
-
쿼리에서 열 별칭을 사용하여 열 레이블을 줄입니다. 각 열 이름은 결과 집합의 각 행에 대한 JSON 문자열에서 반복됩니다. 따라서 열 이름이 길고 행이 많은 쿼리 결과는 크기 제한을 초과할 수 있습니다. 특히 복잡한 표현식에 열 별칭을 사용하면 JSON 문자열에서 전체 표현식이 반복되는 것을 방지할 수 있습니다.
-
SQL을 사용하면 열 별칭을 사용하여 동일한 이름의 열이 두 개 이상 있는 결과 집합을 생성할 수 있지만 JSON에서는 중복 키 이름이 허용되지 않습니다. 결과 집합을 JSON 형식으로 요청하고 둘 이상의 열의 이름이 같은 경우 RDS Data API에서 오류를 반환합니다. 따라서 모든 열 레이블의 이름이 고유하도록 해야 합니다.
예시
다음 Java 예제는 응답이 JSON 형식의 문자열인 ExecuteStatement
를 호출한 후 결과 집합을 해석하는 방법을 보여줍니다. databaseName
, secretStoreArn
및 clusterArn
파라미터를 적절한 값으로 대체합니다.
다음 Java 예제에서는 결과 집합에서 소수 값을 반환하는 쿼리를 보여줍니다. assertThat
호출은 응답 필드에 JSON 결과 집합에 대한 규칙을 기반으로 예상되는 속성이 있는지 테스트합니다.
이 예제는 다음 스키마 및 샘플 데이터에서 작동합니다.
create table test_simplified_json (a float); insert into test_simplified_json values(10.0);
public void JSON_result_set_demo() { var sql = "select * from test_simplified_json"; var request = new ExecuteStatementRequest() .withDatabase(
databaseName
) .withSecretArn(secretStoreArn
) .withResourceArn(clusterArn
) .withSql(sql) .withFormatRecordsAs(RecordsFormatType.JSON); var result = rdsdataClient.executeStatement(request); }
이전 프로그램의 formattedRecords
필드 값은 다음과 같습니다.
[{"a":10.0}]
JSON 결과 집합이 있기 때문에 응답의 Records
및 ColumnMetadata
필드는 모두 Null입니다.
다음 Java 예제에서는 결과 집합에서 정수 값을 반환하는 쿼리를 보여줍니다. 예제는 getFormattedRecords
를 호출하여 JSON 형식의 문자열만 반환하고 비어 있거나 Null인 다른 응답 필드는 무시합니다. 이 예제에서는 결과를 레코드 목록을 나타내는 구조로 역직렬화합니다. 각 레코드에는 이름이 결과 집합의 열 별칭에 해당하는 필드가 있습니다. 이 기법은 결과 집합을 구문 분석하는 코드를 단순화합니다. 애플리케이션에서 결과 집합의 행과 열을 반복하여 각 값을 적절한 유형으로 변환할 필요가 없습니다.
이 예제는 다음 스키마 및 샘플 데이터에서 작동합니다.
create table test_simplified_json (a int); insert into test_simplified_json values(17);
public void JSON_deserialization_demo() { var sql = "select * from test_simplified_json"; var request = new ExecuteStatementRequest() .withDatabase(
databaseName
) .withSecretArn(secretStoreArn
) .withResourceArn(clusterArn
) .withSql(sql) .withFormatRecordsAs(RecordsFormatType.JSON); var result = rdsdataClient.executeStatement(request) .getFormattedRecords(); /* Turn the result set into a Java object, a list of records. Each record has a field 'a' corresponding to the column labelled 'a' in the result set. */ private static class Record { public int a; } var recordsList = new ObjectMapper().readValue( response, new TypeReference<List<Record>>() { }); }
이전 프로그램의 formattedRecords
필드 값은 다음과 같습니다.
[{"a":17}]
결과 행 0의 a
열을 검색하려면 애플리케이션은 recordsList.get(0).a
를 참조합니다.
반대로 다음 Java 예제에서는 JSON 형식을 사용하지 않을 때 결과 집합을 포함하는 데이터 구조를 구성하는 데 필요한 코드 종류를 보여줍니다. 이 경우 결과 집합의 각 행에는 단일 사용자에 대한 정보가 포함된 필드가 포함됩니다. 결과 집합을 나타내는 데이터 구조를 구축하려면 행을 반복해야 합니다. 각 행에 대해 코드는 각 필드의 값을 검색하고 적절한 형식 변환을 수행하며 행을 나타내는 객체의 해당 필드에 결과를 할당합니다. 그런 다음 코드는 각 사용자를 나타내는 객체를 전체 결과 집합을 나타내는 데이터 구조에 추가합니다. 결과 집합에서 필드를 재정렬, 추가 또는 제거하도록 쿼리가 변경된 경우 애플리케이션 코드도 변경해야 합니다.
/* Verbose result-parsing code that doesn't use the JSON result set format */ for (var row: response.getRecords()) { var user = User.builder() .userId(row.get(0).getLongValue()) .firstName(row.get(1).getStringValue()) .lastName(row.get(2).getStringValue()) .dob(Instant.parse(row.get(3).getStringValue())) .build(); result.add(user); }
다음 샘플 값은 열, 열 별칭 및 열 데이터 유형이 서로 다른 결과 집합에 대한 formattedRecords
필드의 값을 보여줍니다.
결과 집합에 여러 행이 포함된 경우 각 행은 배열 요소인 객체로 표시됩니다. 결과 집합의 각 열은 객체 내에서 키가 됩니다. 키는 결과 집합의 각 행에서 반복됩니다. 따라서 여러 행과 열로 구성된 결과 집합의 경우 전체 응답의 길이 제한을 초과하지 않도록 짧은 열 별칭을 정의해야 할 수 있습니다.
이 예제는 다음 스키마 및 샘플 데이터에서 작동합니다.
create table sample_names (id int, name varchar(128)); insert into sample_names values (0, "Jane"), (1, "Mohan"), (2, "Maria"), (3, "Bruce"), (4, "Jasmine");
[{"id":0,"name":"Jane"},{"id":1,"name":"Mohan"}, {"id":2,"name":"Maria"},{"id":3,"name":"Bruce"},{"id":4,"name":"Jasmine"}]
결과 집합의 열이 표현식으로 정의된 경우 표현식의 텍스트가 JSON 키가 됩니다. 따라서 일반적으로 쿼리의 선택 목록에서 각 표현식에 대한 설명 열 별칭을 정의하는 것이 편리합니다. 예를 들어, 다음 쿼리는 선택 목록에 함수 호출 및 산술 연산과 같은 표현식을 포함합니다.
select count(*), max(id), 4+7 from sample_names;
이러한 표현식은 키로 JSON 결과 집합을 통해 전달됩니다.
[{"count(*)":5,"max(id)":4,"4+7":11}]
설명 레이블이 있는 AS
열을 추가하면 JSON 결과 집합에서 키를 보다 간단하게 해석할 수 있습니다.
select count(*) as rows, max(id) as largest_id, 4+7 as addition_result from sample_names;
수정된 SQL 쿼리의 경우, AS
절에 의해 정의된 열 레이블이 키 이름으로 사용됩니다.
[{"rows":5,"largest_id":4,"addition_result":11}]
JSON 문자열의 각 키 값 쌍의 값은 따옴표로 묶인 문자열일 수 있습니다. 문자열에는 유니코드 문자가 포함될 수 있습니다. 문자열에 이스케이프 시퀀스가 포함되어 있거나 "
또는 \
문자가 포함되어 있는 경우 이러한 문자 앞에는 백슬래시 이스케이프 문자가 있습니다. 다음 JSON 문자열의 예제는 이러한 가능성을 보여줍니다. 예를 들어 string_with_escape_sequences
결과에는 특수 문자 백스페이스, 줄 바꿈, 캐리지 리턴, 탭, 양식 피드 및 \
가 포함됩니다.
[{"quoted_string":"hello"}] [{"unicode_string":"邓不利多"}] [{"string_with_escape_sequences":"\b \n \r \t \f \\ '"}]
JSON 문자열의 각 키 값 쌍의 값은 숫자를 나타낼 수도 있습니다. 숫자는 정수, 부동 소수점 값, 음수 값 또는 지수 표기법으로 표현되는 값일 수 있습니다. 다음 JSON 문자열의 예제는 이러한 가능성을 보여줍니다.
[{"integer_value":17}] [{"float_value":10.0}] [{"negative_value":-9223372036854775808,"positive_value":9223372036854775807}] [{"very_small_floating_point_value":4.9E-324,"very_large_floating_point_value":1.7976931348623157E308}]
부울 값과 Null 값은 따옴표 없는 특수 키워드 true
, false
및 null
로 표현됩니다. 다음 JSON 문자열의 예제는 이러한 가능성을 보여줍니다.
[{"boolean_value_1":true,"boolean_value_2":false}] [{"unknown_value":null}]
BLOB 유형의 값을 선택하면 결과가 JSON 문자열에서 base64로 인코딩된 값으로 표시됩니다. 값을 원래 표현으로 다시 변환하려면 애플리케이션의 언어로 적절한 디코딩 기능을 사용할 수 있습니다. 예를 들어 Java에서는 Base64.getDecoder().decode()
함수를 호출합니다. 다음 샘플 출력은 hello world
의 BLOB 값을 선택하고 결과 집합을 JSON 문자열로 반환한 것을 보여줍니다.
[{"blob_column":"aGVsbG8gd29ybGQ="}]
다음 Python 예제는 Python execute_statement
함수에 대한 호출의 결과에서 값에 액세스하는 방법을 보여줍니다. 결과 집합은 필드 response['formattedRecords']
의 문자열 값입니다. 이 코드는 json.loads
함수를 호출하여 JSON 문자열을 데이터 구조로 변환합니다. 그러면 결과 집합의 각 행은 데이터 구조 내의 목록 요소이며 각 행 내에서 이름으로 결과 집합의 각 필드를 참조할 수 있습니다.
import json result = json.loads(response['formattedRecords']) print (result[0]["id"])
다음 JavaScript 예제는 JavaScript executeStatement
함수에 대한 호출의 결과에서 값에 액세스하는 방법을 보여줍니다. 결과 집합은 필드 response.formattedRecords
의 문자열 값입니다. 이 코드는 JSON.parse
함수를 호출하여 JSON 문자열을 데이터 구조로 변환합니다. 그러면 결과 집합의 각 행은 데이터 구조 내의 배열 요소이며 각 행 내에서 이름으로 결과 집합의 각 필드를 참조할 수 있습니다.
<script> const result = JSON.parse(response.formattedRecords); document.getElementById("display").innerHTML = result[0].id; </script>