Shape / inspect · All operations

Check a table's structure

A variant of Check data quality

Check that a table has the expected columns, names and types, failing or conforming it when it does not.

Status

In arcform

Runs as a SQL step

arcform carries it as a sql: step today.

The DuckDB step

Check a table has the expected columns, names and types, and conform it when it does not

SQL
-- what arrived: ids and amounts as text, no order_date, and a column nobody asked for
CREATE TEMP TABLE arrived AS SELECT * FROM (VALUES
  ('1', 'Alice Ng', '120.5', 'first'), ('2', 'Bob Okafor', 'n/a', 'second')) t(order_id, customer, amount, note);
CREATE TEMP TABLE expected_structure AS SELECT * FROM (VALUES
  ('order_id', 'BIGINT'), ('customer', 'VARCHAR'), ('amount', 'DOUBLE'), ('order_date', 'DATE')) t(column_name, column_type);
-- read the structure from DESCRIBE, then compare it with the expectation in both directions
CREATE TEMP TABLE problems AS
SELECT coalesce(e.column_name, a.column_name) AS column_name,
       CASE WHEN a.column_name IS NULL THEN 'missing'
            WHEN e.column_name IS NULL THEN 'unexpected'
            ELSE 'wrong type: ' || a.column_type END AS problem
FROM expected_structure e FULL OUTER JOIN (SELECT column_name, column_type FROM (DESCRIBE arrived)) a USING (column_name)
WHERE a.column_name IS NULL OR e.column_name IS NULL OR a.column_type <> e.column_type;
-- conform: cast to the expected types (a value that does not fit becomes NULL), add the missing column, drop the extra one
CREATE TEMP TABLE conformed AS
SELECT TRY_CAST(order_id AS BIGINT) AS order_id, customer, TRY_CAST(amount AS DOUBLE) AS amount, CAST(NULL AS DATE) AS order_date FROM arrived;
CREATE TEMP TABLE problems_after AS
SELECT coalesce(e.column_name, a.column_name) AS column_name FROM expected_structure e
FULL OUTER JOIN (SELECT column_name, column_type FROM (DESCRIBE conformed)) a USING (column_name)
WHERE a.column_name IS NULL OR e.column_name IS NULL OR a.column_type <> e.column_type;
SELECT * FROM problems ORDER BY column_name;
SELECT * FROM conformed ORDER BY order_id;
SELECT CASE WHEN ((SELECT list((column_name, problem) ORDER BY column_name) FROM problems) = [('amount', 'wrong type: VARCHAR'), ('note', 'unexpected'), ('order_date', 'missing'), ('order_id', 'wrong type: VARCHAR')] AND (SELECT count(*) FROM problems_after) = 0 AND (SELECT list(column_name) FROM (DESCRIBE conformed)) = ['order_id', 'customer', 'amount', 'order_date'] AND (SELECT list((order_id, amount) ORDER BY order_id) FROM conformed) IS NOT DISTINCT FROM [(1, 120.5), (2, NULL)]) THEN 'as expected' ELSE error('the arrived table should have four structure problems, and the conformed table none, with the amount n/a turned to NULL') END AS verdict;
  • The statement builds its own data.
  • It needs nothing installed beyond DuckDB itself.
  • The statement checks its own result and raises an error when it is wrong: “the arrived table should have four structure problems, and the conformed table none, with the amount n/a turned to NULL”.
  • 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).

AWS Glue (4)
  • ColumnCountread 2026-09-27

    Check the number of columns, to catch dropped columns

  • ColumnExistsread 2026-09-27

    Check that a column exists in the dataset

  • Check that column names match a pattern

  • SchemaMatchread 2026-09-27

    Check that the schemas of two datasets match

KNIME Analytics Platform (3)
  • Check a table's columns, types and domains against a second reference table and conform it

  • Check that a table matches a reference column structure set in the dialog, fixing or failing

  • Table Validatorread 2026-09-27

    Check table structure and content against a specification set in the dialog

Polars (1)
  • Check a frame against a target schema, erroring or coercing on missing, extra or mistyped columns

Power Query M (1)
  • Table.HasColumnsread 2026-09-27

    Report whether the table has the named column or columns

RapidMiner Studio (1)
  • Check whether a table's columns and values are compatible with a model's training data

Background

In Polars, match_to_schema matches or evolves a frame's schema into a target schema, and by default returns an error if the two do not exactly match.[1] In DuckDB, DESCRIBE followed by a table name shows the schema of the table, and DESCRIBE put before a query shows the schema of the query's result.[2] DuckDB's information_schema views are Structured Query Language (SQL) standard views that describe the catalogue entries of the database.[3]

When to use it

In Amazon Web Services (AWS) Glue Data Quality, the ColumnCount rule checks whether any columns are dropped and the ColumnExists rule checks that columns exist.[4] Check structure first on any table that arrives from outside, since a renamed or dropped column breaks every rule that names it. (Meridian's view)

DuckDB's comma-separated values (CSV) reader detects column types from a sample of the file, 20,480 rows by default.[5] In DuckDB's CSV type detection, VARCHAR is the fallback, so columns that cannot be cast to any other candidate type are read as VARCHAR.[5] Check detected types against the expected structure on every load, not only the first, because a new file can bring a value that changes what is detected. (Meridian's view)

Polars' match_to_schema can be told to insert missing columns, to ignore extra columns, and to upcast integer or float columns.[1] Decide for each column whether a missing column, an extra column or a changed type should stop the load or be conformed, and write that decision down beside the expected structure. (Meridian's view)

The method

DuckDB's information_schema.columns view gives each column's ordinal position, whether it is nullable, and its data type, such as DECIMAL(18, 2).[3] In DuckDB, DESCRIBE can be used as a subquery, which allows creating a table from the description.[2] Hold the expected structure as a small table of column names and types and compare it with DESCRIBE's output by a full outer join, which names the missing, unexpected and retyped columns at once. (Meridian's view) Compare full type names, precision and scale included, since a DECIMAL(18, 2) that arrives as DECIMAL(18, 3) is a change worth seeing. (Meridian's view)