본문 바로가기
WIKI 기술 지식 베이스

JSON 함수

원문 보기 위키 갱신

JSON 함수 (JSON Functions)

Turso는 SQLite JSON1 확장과 호환되는 JSON 함수들을 모두 갖추고 있어요. 이 함수들은 TEXT로 저장된 JSON이나 Turso의 내부 이진 JSON(JSONB) 형식으로 저장된 JSON을 다뤄요.

출처: 문서

본문

함수 대부분이 짝을 이루고 있어요: TEXT를 반환하는 json_* 변형과 내부 이진 형식의 BLOB을 반환하는 jsonb_* 변형이 그거예요. JSONB 변형은 결과를 애플리케이션에 돌려주는 게 아니라 저장하거나 다른 JSON 함수에 넘길 때 더 효율적이에요.

JSON 경로 문법

많은 JSON 함수가 JSON 문서 안의 특정 원소를 가리키는 경로(path) 인수를 받아요.

문법 의미
$ 루트 원소
$.key key라는 이름의 객체 멤버
$[N] 인덱스 N의 배열 원소 (0부터 시작)
$.key1.key2 중첩된 객체 멤버
$.key[0] 객체 멤버 안 배열의 첫 번째 원소
$[0].key 첫 번째 배열 원소 안의 객체 멤버

경로 인수는 반드시 $로 시작해야 해요. 경로가 어떤 원소와도 일치하지 않으면 함수는 보통 NULL을 반환해요.

SELECT json_extract('{"a": {"b": [10, 20, 30]}}', '$.a.b[1]');
-- 20

JSON 생성과 검증

json

JSON 문자열을 검증하고 압축(minified) 형태로 반환해요. 입력이 유효한 JSON이 아니면 오류가 발생해요.

json(json_text)
매개변수 타입 설명
json_text TEXT 검증하고 압축할 JSON 문자열

반환: TEXT -- 압축된 JSON 문자열.

SELECT json('  { "name": "Alice" ,  "age": 30 } ');
-- {"name":"Alice","age":30}

jsonb

JSON 문자열을 내부 이진 JSON 형식으로 바꿔요.

jsonb(json_text)
매개변수 타입 설명
json_text TEXT 변환할 JSON 문자열

반환: BLOB -- 이진 JSON 형식의 값.

SELECT typeof(jsonb('{"a":1}'));
-- blob

json_array / jsonb_array

인수들로 JSON 배열을 만들어요.

json_array(value1, value2, ...)
jsonb_array(value1, value2, ...)
매개변수 타입 설명
value1, value2, ... any 배열에 넣을 값. SQL NULL은 JSON null이 돼요.

반환: TEXT (json_array) 또는 BLOB (jsonb_array) -- JSON 배열.

SELECT json_array(1, 'hello', NULL, 3.14);
-- [1,"hello",null,3.14]

SELECT json_array();
-- []

json_object / jsonb_object

label/value 쌍을 번갈아 나열해서 JSON 객체를 만들어요. *로 호출하면 그 행의 모든 컬럼을 컬럼 이름을 키로 써서 label/value 쌍으로 펼쳐요.

json_object(label1, value1, label2, value2, ...)
jsonb_object(label1, value1, label2, value2, ...)
json_object(*)
매개변수 타입 설명
label1, label2, ... TEXT JSON 객체의 키. 반드시 문자열이어야 해요.
value1, value2, ... any 대응하는 값. SQL NULL은 JSON null이 돼요.

반환: TEXT (json_object) 또는 BLOB (jsonb_object) -- JSON 객체.

SELECT json_object('name', 'Alice', 'age', 30);
-- {"name":"Alice","age":30}

SELECT json_object('items', json_array(1, 2, 3));
-- {"items":[1,2,3]}

json_quote

SQL 값을 JSON 표현으로 바꿔요.

json_quote(value)
매개변수 타입 설명
value any JSON으로 인용할 SQL 값

반환: TEXT -- 값의 JSON 표현.

SELECT json_quote('hello');
-- "hello"

SELECT json_quote(42);
-- 42

SELECT json_quote(NULL);
-- null

json_valid

인수가 올바른 형태의 JSON이면 1, 아니면 0을 반환해요.

json_valid(json_text)
매개변수 타입 설명
json_text TEXT 유효한 JSON인지 검사할 문자열

반환: INTEGER -- 유효한 JSON이면 1, 아니면 0.

SELECT json_valid('{"name":"Alice"}');
-- 1

SELECT json_valid('not json');
-- 0

SELECT json_valid(NULL);
-- 0

json_error_position

JSON 문자열에서 첫 번째 문법 오류의 문자 위치를 반환하고, 문자열이 유효한 JSON이면 0을 반환해요.

json_error_position(json_text)
매개변수 타입 설명
json_text TEXT JSON 오류를 검사할 문자열

반환: INTEGER -- 첫 번째 오류의 문자 위치 (1부터 시작), 유효하면 0.

SELECT json_error_position('{"a":1}');
-- 0

SELECT json_error_position('{"a":}');
-- 6

JSON 추출

json_extract / jsonb_extract

경로 인수로 JSON 문서에서 하나 이상의 값을 꺼내요.

json_extract(json_text, path)
json_extract(json_text, path1, path2, ...)
jsonb_extract(json_text, path)
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT JSON 경로 표현식 하나 이상

반환: 경로가 하나면, 꺼낸 값을 자연스러운 SQL 타입(INTEGER, REAL, TEXT, NULL)으로 반환해요. JSON 객체와 배열은 TEXT로 반환돼요. 경로가 여러 개면, 꺼낸 값들을 JSON 배열로 반환해요. jsonb_extract는 BLOB을 반환해요.

SELECT json_extract('{"name":"Alice","age":30}', '$.name');
-- Alice

SELECT json_extract('{"name":"Alice","age":30}', '$.age');
-- 30

-- Multiple paths return a JSON array
SELECT json_extract('{"a":1,"b":2,"c":3}', '$.a', '$.c');
-- [1,3]

-> 연산자

JSON에서 값을 꺼내서 JSON으로 반환해요. 항상 JSON 텍스트를 반환하는 json_extract의 축약형이에요 (객체와 배열은 JSON 그대로, 문자열은 JSON 인용을 붙여서).

json_text -> path
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT JSON 경로 표현식

반환: TEXT -- JSON 형태로 꺼낸 값.

SELECT '{"name":"Alice"}' -> '$.name';
-- "Alice"

SELECT '{"items":[1,2,3]}' -> '$.items';
-- [1,2,3]

->> 연산자

JSON에서 값을 꺼내서 SQL 값으로 반환해요. 문자열은 인용이 벗겨지고, 숫자는 INTEGER 또는 REAL로, 불리언은 정수(0 또는 1)로 반환돼요.

json_text ->> path
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT JSON 경로 표현식

반환: 자연스러운 SQL 타입(TEXT, INTEGER, REAL, NULL)으로 꺼낸 값.

SELECT '{"name":"Alice"}' ->> '$.name';
-- Alice

SELECT '{"count":42}' ->> '$.count';
-- 42

json_type

JSON 값의 타입을 문자열로 반환해요: "null", "true", "false", "integer", "real", "text", "array", "object".

json_type(json_text)
json_type(json_text, path)
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT 선택. 들여다볼 JSON 경로. 생략하면 루트를 검사해요.

반환: TEXT -- JSON 타입 이름.

SELECT json_type('{"a":1}');
-- object

SELECT json_type('[1, 2, 3]');
-- array

SELECT json_type('{"a": 1}', '$.a');
-- integer

SELECT json_type('{"a": "hello"}', '$.a');
-- text

JSON 수정

json_insert / jsonb_insert

JSON 문서에 새 값을 넣어요. 기존 값은 덮어쓰지 않아요. 경로가 이미 존재하면 값은 그대로 유지돼요.

json_insert(json_text, path1, value1, path2, value2, ...)
jsonb_insert(json_text, path1, value1, path2, value2, ...)
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT 값을 넣을 JSON 경로
value any 넣을 값

반환: TEXT (json_insert) 또는 BLOB (jsonb_insert) -- 수정된 JSON.

SELECT json_insert('{"a":1}', '$.b', 2);
-- {"a":1,"b":2}

-- Existing values are NOT overwritten
SELECT json_insert('{"a":1}', '$.a', 99);
-- {"a":1}

json_replace / jsonb_replace

JSON 문서의 기존 값을 바꿔요. 경로가 존재하지 않으면 아무것도 넣지 않아요.

json_replace(json_text, path1, value1, path2, value2, ...)
jsonb_replace(json_text, path1, value1, path2, value2, ...)
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT 바꿀 값을 가리키는 JSON 경로
value any 교체할 값

반환: TEXT (json_replace) 또는 BLOB (jsonb_replace) -- 수정된 JSON.

SELECT json_replace('{"a":1,"b":2}', '$.a', 99);
-- {"a":99,"b":2}

-- Non-existent paths are ignored
SELECT json_replace('{"a":1}', '$.b', 2);
-- {"a":1}

json_set / jsonb_set

JSON 문서에 값을 넣거나 바꿔요. json_insert와 json_replace의 동작을 합친 거예요: 경로가 있으면 값을 바꾸고, 없으면 값을 넣어요.

json_set(json_text, path1, value1, path2, value2, ...)
jsonb_set(json_text, path1, value1, path2, value2, ...)
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT 값을 가리키는 JSON 경로
value any 설정할 값

반환: TEXT (json_set) 또는 BLOB (jsonb_set) -- 수정된 JSON.

-- Replace existing
SELECT json_set('{"a":1}', '$.a', 99);
-- {"a":99}

-- Insert new
SELECT json_set('{"a":1}', '$.b', 2);
-- {"a":1,"b":2}

json_remove / jsonb_remove

JSON 문서에서 하나 이상의 원소를 제거해요.

json_remove(json_text, path1, path2, ...)
jsonb_remove(json_text, path1, path2, ...)
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT 제거할 JSON 경로 하나 이상

반환: TEXT (json_remove) 또는 BLOB (jsonb_remove) -- 수정된 JSON.

SELECT json_remove('{"a":1,"b":2,"c":3}', '$.b');
-- {"a":1,"c":3}

SELECT json_remove('[1,2,3,4]', '$[1]');
-- [1,3,4]

json_patch / jsonb_patch

JSON 문서에 RFC 7396 병합 패치(merge patch)를 적용해요. 패치의 객체 멤버는 대상의 멤버를 덮어써요. 패치의 null 값은 해당 멤버를 제거해요.

json_patch(json_text, patch)
jsonb_patch(json_text, patch)
매개변수 타입 설명
json_text TEXT or BLOB 대상 JSON 문서
patch TEXT or BLOB 적용할 병합 패치

반환: TEXT (json_patch) 또는 BLOB (jsonb_patch) -- 패치가 적용된 JSON.

SELECT json_patch('{"a":1,"b":2}', '{"b":3,"c":4}');
-- {"a":1,"b":3,"c":4}

-- null in the patch removes a key
SELECT json_patch('{"a":1,"b":2}', '{"b":null}');
-- {"a":1}

json_pretty

JSON 문서를 보기 좋게 출력한(들여쓰기된) 표현을 반환해요.

json_pretty(json_text)
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서

반환: TEXT -- 들여쓰기가 적용된 포맷된 JSON 문자열.

SELECT json_pretty('{"name":"Alice","scores":[90,85,92]}');
/*
{
    "name": "Alice",
    "scores": [
        90,
        85,
        92
    ]
}
*/

JSON 배열 함수

json_array_length

JSON 배열의 원소 개수를 반환해요. 빈 배열이면 0, 배열이 아닌 JSON 값이면 NULL을 반환해요.

json_array_length(json_text)
json_array_length(json_text, path)
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT 선택. 문서 안에서 배열을 가리키는 JSON 경로.

반환: INTEGER -- 원소 개수, 경로의 값이 배열이 아니면 NULL.

SELECT json_array_length('[1, 2, 3, 4]');
-- 4

SELECT json_array_length('{"items": [10, 20]}', '$.items');
-- 2

SELECT json_array_length('{"a": 1}');
-- NULL

JSON 집계 함수

json_group_array / jsonb_group_array

그룹의 값들을 모아서 JSON 배열로 만드는 집계 함수예요.

json_group_array(value)
jsonb_group_array(value)
매개변수 타입 설명
value any 각 행에서 모을 값

반환: TEXT (json_group_array) 또는 BLOB (jsonb_group_array) -- 그룹의 모든 값을 담은 JSON 배열.

CREATE TABLE items (category TEXT, name TEXT);
INSERT INTO items VALUES ('fruit', 'apple'), ('fruit', 'banana'), ('veggie', 'carrot');

SELECT category, json_group_array(name) FROM items GROUP BY category;
-- fruit  | ["apple","banana"]
-- veggie | ["carrot"]

json_group_object / jsonb_group_object

그룹의 label/value 쌍을 모아서 JSON 객체로 만드는 집계 함수예요.

json_group_object(label, value)
jsonb_group_object(label, value)
매개변수 타입 설명
label TEXT 각 항목의 키
value any 각 항목의 값

반환: TEXT (json_group_object) 또는 BLOB (jsonb_group_object) -- JSON 객체.

CREATE TABLE settings (key TEXT, value TEXT);
INSERT INTO settings VALUES ('theme', 'dark'), ('lang', 'en');

SELECT json_group_object(key, value) FROM settings;
-- {"theme":"dark","lang":"en"}

JSON 테이블 값 함수

json_each

JSON 배열이나 객체의 최상위 원소들을 훑으면서 원소마다 한 행을 반환하는 테이블 값 함수예요.

SELECT * FROM json_each(json_text);
SELECT * FROM json_each(json_text, path);
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT 선택. 순회할 배열이나 객체를 가리키는 JSON 경로. 기본값은 $.

출력 컬럼:

컬럼 타입 설명
key TEXT or INTEGER 객체 키(TEXT) 또는 배열 인덱스(INTEGER)
value any 원소의 값. 객체/배열은 JSON 텍스트로, 원시값은 SQL 값으로
type TEXT JSON 타입: null, true, false, integer, real, text, array, object
atom any 원시값의 SQL 값 (배열과 객체는 NULL)
id INTEGER 원소의 순차 식별자
parent INTEGER 부모 원소의 id (최상위는 NULL)
fullkey TEXT 이 원소까지의 전체 JSON 경로
path TEXT 이 원소의 부모를 가리키는 JSON 경로
SELECT key, value, type FROM json_each('[10, "hello", null]');
-- 0 | 10    | integer
-- 1 | hello | text
-- 2 | null  | null

SELECT key, value FROM json_each('{"a":1, "b":2}');
-- a | 1
-- b | 2

-- With a path
SELECT key, value FROM json_each('{"data": [1, 2, 3]}', '$.data');
-- 0 | 1
-- 1 | 2
-- 2 | 3

json_tree

`json_tree`는 부분 지원이에요. 일부 고급 순회 기능은 기대대로 동작하지 않을 수 있어요.

JSON 문서를 재귀적으로 훑으면서, 모든 중첩 수준의 모든 원소마다 한 행을 반환하는 테이블 값 함수예요.

SELECT * FROM json_tree(json_text);
SELECT * FROM json_tree(json_text, path);
매개변수 타입 설명
json_text TEXT or BLOB JSON 문서
path TEXT 선택. 훑을 하위 트리를 가리키는 JSON 경로. 기본값은 $.

출력 컬럼: json_each와 같아요.

SELECT key, value, type, path FROM json_tree('{"a": [1, 2]}');
-- NULL | {"a":[1,2]} | object  | $
-- a    | [1,2]       | array   | $
-- 0    | 1           | integer | $.a
-- 1    | 2           | integer | $.a

실전 예제

JSON 데이터 저장하고 조회하기

CREATE TABLE events (id INTEGER PRIMARY KEY, data TEXT);
INSERT INTO events VALUES (1, '{"type":"click","x":100,"y":200}');
INSERT INTO events VALUES (2, '{"type":"scroll","offset":500}');

-- Extract specific fields
SELECT id, data ->> '$.type' AS event_type FROM events;
-- 1 | click
-- 2 | scroll

-- Filter by JSON value
SELECT * FROM events WHERE data ->> '$.type' = 'click';

JSON 제자리에서 수정하기

UPDATE events
SET data = json_set(data, '$.timestamp', '2025-01-15T10:30:00Z')
WHERE id = 1;

SELECT data FROM events WHERE id = 1;
-- {"type":"click","x":100,"y":200,"timestamp":"2025-01-15T10:30:00Z"}

관계형 데이터로 JSON 만들기

CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT);
INSERT INTO users VALUES (1, 'Alice', '[email protected]');
INSERT INTO users VALUES (2, 'Bob', '[email protected]');

SELECT json_object('users', json_group_array(
    json_object('id', id, 'name', name, 'email', email)
)) FROM users;
-- {"users":[{"id":1,"name":"Alice","email":"[email protected]"},{"id":2,"name":"Bob","email":"[email protected]"}]}

json_each로 JSON 배열 펼치기

CREATE TABLE orders (id INTEGER PRIMARY KEY, items TEXT);
INSERT INTO orders VALUES (1, '["widget","gadget","gizmo"]');
INSERT INTO orders VALUES (2, '["sprocket"]');

-- Expand each order's items into individual rows
SELECT orders.id, each.value AS item
FROM orders, json_each(orders.items) AS each;
-- 1 | widget
-- 1 | gadget
-- 1 | gizmo
-- 2 | sprocket

더 알아보기 (Learn more)

  • 데이터 타입 - JSON 값이 SQL 타입으로 매핑되는 방식
  • 표현식 - 표현식 안에서 JSON 연산자 사용하기