Shape / columns · All operations
Spread nested fields into columns
A variant of Parse nested values
Lift every field of a struct or object column into its own top-level column, one row still per row.
Status
- In arcform
Runs as a SQL step
arcform carries it as a
sql:step today.
The DuckDB step
Spread the fields of a struct into top-level columns, one row per row
It reads the orders table the proofs share. Create it first:
CREATE TABLE orders AS SELECT * FROM (VALUES
(1, 'Alice Ng', 'north', DATE '2026-01-03', 120.00, 'widget', 'a|b', '{"channel":"web","items":[1,2]}'),
(2, 'alice ng', 'north', DATE '2026-01-05', 80.50, 'gadget', 'b', '{"channel":"shop","items":[3]}'),
(3, 'Bob Okafor', 'south', DATE '2026-01-05', 300.00, 'widget', 'a|c', '{"channel":"web","items":[4,5,6]}'),
(4, 'Carla Díaz', 'east', DATE '2026-01-09', NULL, 'gizmo', NULL, '{"channel":"web","items":[]}'),
(5, 'Bob Okafor', 'south', DATE '2026-01-12', 45.25, 'gadget', 'c', '{"channel":"phone","items":[7]}'),
(6, 'Dev Patel', 'west', DATE '2026-01-12', 510.00, 'widget', 'a', '{"channel":"web","items":[8,9]}'),
(7, 'Carla Diaz', 'east', DATE '2026-01-20', 99.99, 'gizmo', 'b|c', '{"channel":"shop","items":[10]}'),
(8, 'Dev Patel', 'west', DATE '2026-02-02', 510.00, 'widget', 'a', '{"channel":"web","items":[8,9]}'),
(9, 'Eve Larsen', NULL, DATE '2026-02-03', 15.00, 'gadget', NULL, '{"channel":"web","items":[11]}'),
(10, 'Alice Ng', 'north', DATE '2026-02-10', 220.00, 'gizmo', 'a|b|c', '{"channel":"phone","items":[12,13]}')
) t(order_id, customer, region, order_date, amount, product, tags, meta);Then run the statement:
CREATE TEMP TABLE raw AS
SELECT order_id, meta FROM orders UNION ALL SELECT 11, NULL;
CREATE TEMP TABLE result AS
SELECT order_id, s.* FROM (SELECT order_id, from_json(meta, '{"channel":"VARCHAR","items":["INTEGER"]}') AS s FROM raw);
SELECT * FROM result ORDER BY order_id;
DESCRIBE result;
SELECT CASE WHEN ((SELECT list(column_name) FROM (DESCRIBE result)) = ['order_id', 'channel', 'items'] AND (SELECT count(*) FROM result) = 11 AND (SELECT items FROM result WHERE order_id = 3) = [4, 5, 6] AND (SELECT count(*) FROM result WHERE order_id = 11 AND channel IS NULL AND items IS NULL) = 1) THEN 'as expected' ELSE error('the struct was not spread into a channel column and an items column with one row per row, or a missing struct lost its row') END AS verdict;- It needs nothing installed beyond DuckDB itself.
- The statement checks its own result and raises an error when it is wrong: “the struct was not spread into a channel column and an items column with one row per row, or a missing struct lost its row”.
- It passed on DuckDB
v2.0.0 (Cyanoptera) d54cbbe3df.
What other tools call it
Meridian's classification; an independent blind rating agreed on 95.7% of 324 rows (variant, version 3).
Alteryx Designer (1)
XML Parseread 2026-09-27Parse XML text into individual fields
Apache DataFusion (1)
unnest (struct)read 2026-09-27Expand the fields of a struct into individual columns
Apache NiFi (1)
FlattenJsonread 2026-09-27Flatten a nested JSON document into single-level keys joined by a separator
AWS Glue (4)
Flattenread 2026-09-27Lift the fields inside structs to top-level fields
Simplify_ddb_jsonread 2026-09-27Simplify nested columns that are in the DynamoDB JSON structure
UnnestFrameread 2026-09-27Flatten nested objects to top-level fields and generate join keys for array objects
unnest_ddb_jsonread 2026-09-27Flatten nested columns that are in the DynamoDB JSON structure
Duckle (1)
Flattenread 2026-09-25flatten nested JSON into columns
KNIME Analytics Platform (1)
JSON to Tableread 2026-09-27Flatten a JSON column into columns by inferring its structure
Polars (1)
DataFrame.unnestread 2026-09-27Spread the fields of struct columns into separate columns
Power Query M (1)
Table.ExpandRecordColumnread 2026-09-27Spread the fields of a record-valued column into separate columns
Talend (1)
tExtractDynamicFieldsread 2026-09-27Parse a column of Dynamic type into standard output columns
Trifacta (2)
Unnest Transformread 2026-09-27Unpack keys of an Object or elements of an Array into new columns
Unnest elementsread 2026-09-27Extract elements of an Object or Array into columns
VisiData (8)
contract-colread 2026-09-23Remove expanded child columns and restore the parent column
contract-col-depthread 2026-09-23Contract current column's expansion to a given depth
contract-colsread 2026-09-23Remove all expanded child columns and restore their parents
contract-cols-depthread 2026-09-23Contract all expansions to a given depth
expand-colread 2026-09-23Expand current column of lists or dicts into one column per key, one level
expand-col-depthread 2026-09-23Expand current column of lists or dicts to a given depth
expand-colsread 2026-09-23Expand all visible columns of lists or dicts one level
expand-cols-depthread 2026-09-23Expand all visible columns of lists or dicts to a given depth
Background
In DuckDB, unnesting a STRUCT value creates a column for each member, the member key becoming the column name and the member value the column value.[1] In DuckDB, a STRUCT can also be spread with the dot-star shorthand s.*, though the unnest function offers some additional functionality.[1]
When to use it
In DuckDB, unnesting a struct is particularly useful when a prior operation creates a struct of unknown shape, or when a query must handle any keys the struct may have.[2] Check whether a column is a struct or a list before unnesting it, and count rows before and after whenever it is a list. (Meridian's view)
By default, DuckDB's unnest unpacks only the outermost level, and its recursive and max_depth parameters carry the unnesting further down.[1] When DuckDB recursively unnests a STRUCT, STRUCT members are unnested further while LIST members are left packed.[1]
The method
DuckDB's read_json can unpack the records of a JavaScript Object Notation (JSON) file into columns, and with records set to false it returns a single STRUCT column instead.[3] DuckDB's Avro reader turns the entries of a single top-level record into top-level columns.[4]
Sources
- [1]Unnesting – DuckDBdocumentation
- [2]Struct Data Type – DuckDBdocumentation
- [3]Loading JSON – DuckDBdocumentation
- [4]Avro Extension – DuckDBdocumentation