JSON_TABLE
Shred a JSON document into relational rows and columns using a declarative SQL function.
JSON_TABLE json_to_recordset FLATTEN OPENJSON JSON_EACH json_array_elements
JSON JSON_TABLE shredding table function OPENJSON
| Database | Status | Syntax Family | Min Version |
|---|---|---|---|
| PostgreSQL | full | json-to-recordset | - |
| MySQL | full | json-table | 8.0 |
| MariaDB | full | json-table | 10.6 |
| Oracle | full | json-table | 12.2 |
| SQL Server | full | openjson | - |
| SQLite | full | json-each | - |
| Redshift | full | partiql-unnest | - |
| DB2 | full | - | - |
| Snowflake | full | flatten | - |
| BigQuery | full | unnest-json | - |
Compare Databases
Database Details
PostgreSQL
full
-- Expand an array of JSON objects into rows
SELECT t.id, t.name
FROM departments d,
json_to_recordset(d.employees) AS t(id INT, name TEXT);
-- Expand a simple JSON array
SELECT elem
FROM json_array_elements('[1,2,3]'::json) AS elem;
-- Key-value iteration
SELECT key, value
FROM json_each('{"a":1,"b":2}'::json);- No JSON_TABLE function. Uses json_to_recordset(json_col) AS t(col1 type, col2 type) for array-of-objects expansion.
- json_each() / json_each_text() iterate over top-level key-value pairs.
- json_array_elements() / jsonb_array_elements() unnest a JSON array into rows.
- Output columns must be declared explicitly in the AS clause for json_to_recordset.
MySQL
full
SELECT jt.id, jt.name
FROM departments d,
JSON_TABLE(
d.employees,
'$[*]' COLUMNS (
id INT PATH '$.id',
name VARCHAR(100) PATH '$.name'
)
) AS jt;- Full SQL:2016 JSON_TABLE with a COLUMNS clause.
- Supports NESTED PATH for expanding nested arrays into additional rows.
- ON EMPTY and ON ERROR clauses control handling of missing or malformed values.
Docs: JSON_TABLE
MariaDB
full
SELECT jt.id, jt.name
FROM departments d,
JSON_TABLE(
d.employees,
'$[*]' COLUMNS (
id INT PATH '$.id',
name VARCHAR(100) PATH '$.name'
)
) AS jt;- JSON_TABLE added in MariaDB 10.6 with the same SQL:2016 syntax as MySQL.
- Supports NESTED PATH for expanding nested arrays.
Docs: JSON_TABLE
Oracle
full
SELECT jt.id, jt.name
FROM departments d,
JSON_TABLE(
d.employees,
'$[*]' COLUMNS (
id NUMBER PATH '$.id',
name VARCHAR2(100) PATH '$.name'
)
) jt;- JSON_TABLE available since Oracle 12.2.
- Supports NESTED PATH for expanding nested JSON arrays into additional rows.
- ERROR ON ERROR / NULL ON ERROR clauses control error handling.
Docs: JSON_TABLE
SQL Server
full
-- OPENJSON with explicit schema (WITH clause)
SELECT jt.id, jt.name
FROM departments d
CROSS APPLY OPENJSON(d.employees, '$')
WITH (
id INT '$.id',
name NVARCHAR(100) '$.name'
) AS jt;
-- OPENJSON without schema returns key/value/type rows
SELECT [key], value, type
FROM OPENJSON('{"a":1,"b":"hello"}');- OPENJSON is the SQL Server equivalent of JSON_TABLE, using a WITH clause instead of COLUMNS.
- Without WITH, OPENJSON returns a generic (key, value, type) rowset.
- Requires compatibility level 130 (SQL Server 2016+).
Docs: OPENJSON
SQLite
full
-- Expand a JSON array
SELECT value
FROM json_each('[1,2,3]');
-- Expand an array of objects stored in a column
SELECT
json_extract(e.value, '$.id') AS id,
json_extract(e.value, '$.name') AS name
FROM departments d,
json_each(d.employees) e;- json_each(json, path) is a table-valued function that expands a JSON array into rows.
- json_tree(json, path) performs recursive traversal of any JSON value.
- No JSON_TABLE; column values must be extracted manually with json_extract().
Docs: json_each and json_tree
Redshift
full
-- Unnest a JSON array stored in SUPER
SELECT
elem.id,
elem.name
FROM departments d,
d.employees AS elem;
-- Equivalent UNNEST form
SELECT elem
FROM departments d,
UNNEST(d.employees) AS elem;- Redshift uses PartiQL iteration and UNNEST over SUPER values rather than a JSON_TABLE function name.
- SUPER arrays can be expanded to rows directly in the FROM clause.
- Object unpivoting is also supported for JSON object shredding.
DB2
full
-- Db2 JSON_TABLE (newer versions)
SELECT jt.id, jt.name
FROM departments d,
JSON_TABLE(
d.employees,
'$[*]' COLUMNS (
id INTEGER PATH '$.id',
name VARCHAR(100) PATH '$.name'
)
) AS jt;- Db2 documents a native JSON_TABLE function.
- XMLTABLE-based approaches were used in older versions before native JSON_TABLE support.
- Supports the SQL/JSON row-and-column shredding pattern directly.
Docs: JSON_TABLE in Db2
Snowflake
full
SELECT
f.value:id::INTEGER AS id,
f.value:name::STRING AS name
FROM departments d,
LATERAL FLATTEN(input => PARSE_JSON(d.employees)) f;- FLATTEN(input, path, outer, recursive, mode) is the Snowflake equivalent of JSON_TABLE.
- Returns columns: SEQ, KEY, PATH, INDEX, VALUE, THIS.
- Element fields are accessed with the colon operator: f.value:field_name.
- LATERAL FLATTEN is the standard usage pattern within a FROM clause.
BigQuery
full
-- Expand a JSON array column
SELECT
JSON_VALUE(elem, '$.id') AS id,
JSON_VALUE(elem, '$.name') AS name
FROM departments d,
UNNEST(JSON_QUERY_ARRAY(d.employees, '$')) AS elem;
-- Native ARRAY of STRUCT avoids JSON entirely
SELECT emp.id, emp.name
FROM departments d,
UNNEST(d.employees_struct) AS emp;- JSON_QUERY_ARRAY(json_col, path) extracts a JSON array; UNNEST() expands it into rows.
- JSON_VALUE() and JSON_QUERY() extract scalars and sub-objects respectively.
- Native STRUCT and ARRAY types are the idiomatic BigQuery alternative to JSON shredding.
- No JSON_TABLE function name, but the shredding capability is present through JSON_QUERY_ARRAY plus UNNEST.
Docs: JSON Functions, Working with JSON