Skip to content
Reference/SQL Schemas
Reference

SQL Schemas

A schema is a folder for database objects. It keeps raw, staging, and reporting tables from colliding, and makes it obvious which is which.

A schema is a named group of objects inside a database. Tables, views, sequences, and macros all live in one. Two schemas can each hold a table called orders without conflict, because the full name of an object includes the schema it sits in.

Create one and put something in it
create schema reporting;

create table reporting.category_revenue as
select p.category_id,
       sum(oi.quantity * oi.unit_price) as revenue
from order_items oi
join products p on p.product_id = oi.product_id
group by p.category_id;

select * from reporting.category_revenue
order by revenue desc, category_id;

Objects you create without naming a schema go into main, which is where everything on the rest of this site lives.

Watch out

Creating a schema that already exists is an error, so useCREATE SCHEMA IF NOT EXISTS in any script you expect to run more than once.

Qualified names

A fully qualified name has three parts:database.schema.object. You will mostly write two, and often one.

Written asMeans
category_revenueLook in the current schema.
reporting.category_revenueThat schema, in the current database.
memory.reporting.category_revenueLeaves nothing to interpretation.

Query an object in another schema without qualifying it and DuckDB reportsTable with name category_revenue does not exist! — usually with aDid you mean "reporting.category_revenue"? hint, which is the fastest way to spot that you forgot the prefix.

Switching schemas

USE changes which schema unqualified names resolve to, so you can stop typing the prefix while working inside one area.

Change the default
use reporting;

-- no prefix needed now
select * from category_revenue;

-- and back
use memory.main;

Tables in main stay reachable while you are in another schema, soUSE adds a place to look rather than cutting you off from the rest of the database. select current_schema() tells you where you are.

Watch out

USE is a per-connection setting. In the SQLShed playground each Run is a new connection, so a USE from one Run does not carry into the next — put it at the top of the same script that depends on it.

What to name them

The convention most teams land on describes how finished the data is, not who owns it:

SchemaHolds
rawLoaded exactly as it arrived. Never edited by hand.
stagingCleaned and typed, not yet joined into anything.
mart / reportingWhat people query. Business names, joins already done.
sandboxWhatever someone is trying today. Droppable without asking.

The value is that the schema name answers "can I trust this table?" before anyone opens it.

Schemas vs databases

A database contains schemas; a schema contains objects. One query can join across schemas in the same database without ceremony. Crossing databases means attaching the other one first, and in DuckDB that is a separateATTACH step. If you are deciding between the two, schemas are almost always what you want — they are lighter, and joins stay simple.

Listing what exists

Schemas, and what is in them
select schema_name
from duckdb_schemas()
where not internal
order by schema_name;

select table_schema, table_name
from information_schema.tables
where table_schema not in ('information_schema')
order by table_schema, table_name;

Cleaning up

Dropping a schema that still contains objects fails with aDependency Error. CASCADE removes the schema and everything inside it, which makes a named schema the tidiest possible sandbox: do the work in it, drop it in one statement, forget nothing.

One statement to clear the bench
drop schema sandbox cascade

See DROP statements for whatCASCADE does and does not reach. You cannot dropmain — DuckDB reports it as an internal system entry.

Dialect note

Schemas are standard, but the layer above them is not. PostgreSQL matches DuckDB closely: databases contain schemas, and cross-database queries need extra machinery. MySQL treats "schema" and "database" as the same thing, so there is no nesting at all. SQL Server puts schemas inside databases inside a server. BigQuery calls the same idea a dataset. The two-partschema.table name is the portable part.