Skip to content

Concepts

Schema files

Declare the relations and functions your SQL reads, so conversion can type it.

Conversion needs to know what each relation and column name refers to and what Snowflake type it has. A schema file declares them as JSON. Pass it with --schema to convert, function, census and index.

{
"ORDERS": [
["ORDER_ID", "NUMBER(38,0)"],
["CUSTOMER_ID", "NUMBER(38,0)"],
["TOTAL", "NUMBER(12,2)"],
["ORDERED_AT", "TIMESTAMP_NTZ"]
]
}

A name the schema does not declare is refused with SQ0004.

Names resolve as Snowflake resolves them. An unquoted name is upper-cased, so FROM orders reads the relation ORDERS. A quoted name keeps its case, so "orders" is a different relation from ORDERS. When a name matches a declared one only ignoring case, the diagnostic says so and suggests the spelling to declare.

Declare a relation as ORDERS, SALES.ORDERS or ANALYTICS.SALES.ORDERS. A qualified name in the SQL, such as analytics.sales.orders in dbt’s compiled models, reads the declared relation whose parts agree with it, and the converted SQL names that relation as declared:

Declared SQL Reads
ORDERS orders, sales.orders, analytics.sales.orders ORDERS
ANALYTICS.SALES.ORDERS orders, sales.orders, Analytics.Sales.Orders ANALYTICS.SALES.ORDERS
ANALYTICS.SALES.ORDERS and ANALYTICS.ARCHIVE.ORDERS sales.orders ANALYTICS.SALES.ORDERS
ANALYTICS.SALES.ORDERS and ANALYTICS.ARCHIVE.ORDERS orders refused: it matches both

The session’s DATABASE and SCHEMA complete a name written without them, as in Snowflake: with --session SCHEMA=archive, orders reads ANALYTICS.ARCHIVE.ORDERS. See Sessions.

These are refused with SQ0004, naming the relations involved:

  • A name matching several declared relations that no session default settles.
  • A qualified name whose declared relation a CTE of the same name hides.
  • Two differently qualified names in one statement that read the same declared relation. Declare each under its qualified name.

The converted SQL reads a qualified relation from the database you attach to DuckDB under that name, such as ATTACH 'analytics.duckdb' AS analytics.

Each column is a [name, type] pair, or an object:

Field Meaning
name The column name.
type Its Snowflake type, such as NUMBER(12,2), VARCHAR or VARIANT.
typed_leaves true when a VARIANT column’s leaves hold typed values. Default false.
offset For a TIMESTAMP_TZ column whose every value has one offset: +00:00 or UTC.

--confirm-declared-offsets lets strict mode rely on the offsets the schema declares.

The top level is either a map of relations, as above, or an object with two sections:

{
"relations": {
"ORDERS": [["ORDER_ID", "NUMBER(38,0)"], ["TOTAL", "NUMBER(12,2)"]]
},
"functions": {
"NET_TOTAL": {
"language": "sql",
"arguments": [["GROSS", "NUMBER(12,2)"]],
"returns": "NUMBER(12,2)"
}
}
}

A function declares its language (sql or python), its arguments as columns, and what it returns. volatility, null_input and vectorized are optional. Unknown fields are rejected.