JSON 타입

JSON 타입

DuckDB는 jsonJSON 논리 타입으로 지원해요. 겉으로는 VARCHAR처럼 보이지만, 값이 '올바른 JSON'이라는 제약이 붙어요. 그래서 유효하지 않은 JSON은 애초에 만들 수가 없죠. JSON 타입의 동작 방식과 캐스팅 규칙을 예시와 함께 살펴볼게요.

출처: 공식문서

기본 동작

SELECT '[1, null, {"key": "value"}]'::JSON;
[1, null, {"key": "value"}]

논리적으로 JSON 타입은 VARCHAR와 비슷하지만, 반드시 유효한 JSON이어야 한다는 제약이 있어요. 물리적으로는 데이터가 VARCHAR로 저장돼요.

그래서 유효하지 않은 JSON은 파싱할 수 없어요:

SELECT 'unquoted'::JSON;
Conversion Error: Malformed JSON at byte 0 of input: unexpected character.  Input: "unquoted"

여기서 원하는 결과라면 아마 SELECT '"quoted"'::JSON을 써야 할 거예요.

데이터가 물리적으로 VARCHAR로 저장되므로 공백도 의미가 있어요:

SELECT '{ "a": 5 }'::JSON = '{"a":5}'::JSON;
false

공백은 왕복(roundtrip) 과정에서 유지된다는 점도 알아두세요:

SELECT '{  "a":5 }'::JSON::VARCHAR
{  "a":5 }

객체에서 키의 순서도 의미가 있어요:

 SELECT '{"a":1,"b":2}'::JSON = '{"b":2,"a":1}'::JSON;
false

JSON 객체에서는 중복 키도 허용돼요:

SELECT '{"a":1,"a":2}'::JSON;
{"a":1,"a":2}

캐스팅 규칙

DuckDB의 어떤 타입이든 JSON으로 캐스팅할 수 있고, JSON도 DuckDB의 어떤 타입으로든 다시 캐스팅할 수 있어요. 예를 들어 JSON을 DuckDB의 STRUCT 타입으로 캐스팅하려면:

SELECT '{"duck": 42}'::JSON::STRUCT(duck INTEGER);
{'duck': 42}

그리고 다시 되돌리려면:

SELECT {duck: 42}::JSON;
{"duck":42}

이 예시처럼 중첩 타입에도 동작하고, 중첩되지 않은 타입에도 마찬가지로 동작해요:

SELECT '2023-05-12'::DATE::JSON;
"2023-05-12"

이 동작의 유일한 예외는 VARCHAR에서 JSON으로의 캐스팅이에요. 이 경우 데이터를 바꾸지 않고, VARCHAR 내용을 JSON으로 파싱하고 검증하기만 해요.

더 알아보기 (Learn more)