List databases and schemas
Short answer: SELECT schema_name FROM information_schema.schemata lists schemas on most engines. Listing databases is engine-specific. Most engines treat each database as an isolated unit you connect to, not something you query across. Postgres has pg_database; MySQL / Snowflake have SHOW DATABASES; BigQuery uses "projects" and "datasets" instead. Know which concept you actually need before reaching for a query.
Database vs schema #
Different engines use these words differently. This is the cause of countless cross-team confusions:
- Postgres / Oracle: a database contains many schemas. You connect to one database; you can query across schemas in that database. Schemas are namespaces for tables.
- MySQL:
databaseandschemaare synonyms — same thing, two words. You can query across them withdb_name.table_name. - SQL Server: a database contains schemas. Defaults often hide them:
dbois the implicit schema if you don't specify one. - Snowflake: account → database → schema → table. Three levels of namespace above tables.
- BigQuery: project → dataset → table. "Dataset" is what other engines call a schema.
- SQLite: a single file is a database; no schemas (you can
ATTACHextra database files).
Canonical SQL #
-- List schemas — works on most engines.
SELECT schema_name
FROM information_schema.schemata
ORDER BY schema_name;
-- Postgres: list databases.
SELECT datname FROM pg_database WHERE datistemplate = FALSE;
\l -- psql shortcut
-- MySQL.
SHOW DATABASES;
SHOW SCHEMAS; -- same thing in MySQL
-- SQL Server.
SELECT name FROM sys.databases;
SELECT * FROM sys.schemas;
-- Snowflake.
SHOW DATABASES;
SHOW SCHEMAS;
SHOW SCHEMAS IN DATABASE my_db;
-- BigQuery.
SELECT schema_name FROM `project_id`.INFORMATION_SCHEMA.SCHEMATA;
-- bq ls --project_id=project_id
-- DuckDB.
SHOW DATABASES;
SHOW SCHEMAS;
-- SQLite.
.databases -- CLI; lists attached databases.Example #
Common variants #
-- Postgres: databases plus their sizes.
SELECT
datname,
pg_size_pretty(pg_database_size(datname)) AS size
FROM pg_database
WHERE datistemplate = FALSE
ORDER BY pg_database_size(datname) DESC;
-- MySQL: databases plus their sizes.
SELECT table_schema AS db,
SUM(data_length + index_length) / 1024 / 1024 AS mb
FROM information_schema.tables
GROUP BY table_schema
ORDER BY mb DESC;
-- Snowflake: get the current account / database / schema you are in.
SELECT CURRENT_ACCOUNT(), CURRENT_DATABASE(), CURRENT_SCHEMA();
-- Postgres: same.
SELECT current_database(), current_schema();
-- Switch.
USE DATABASE my_db; -- Snowflake
USE my_db; -- MySQL
SET search_path = analytics, public; -- Postgres (per session)Dialect notes #
- Postgres:
\llists databases;\dnlists schemas in the current database. Thesearch_pathsetting controls which schemas are searched when an unqualified table name is used. - MySQL: database and schema are aliases.
USE db_nameto switch context;db_name.table_nameto query across without switching. - SQL Server:
USE db_nameto switch. Default schema is usuallydbo.SELECT * FROM other_db.schema.tablefor cross-database queries. - Snowflake: object hierarchy is account → database → schema → table. Use fully-qualified names (
db.schema.table) when querying across schemas.USE DATABASE,USE SCHEMAto set context. - BigQuery: project → dataset → table; queries always need at minimum
dataset.table, oftenproject.dataset.table. NoUSEstatement: context is set per-query or via tooling defaults. - DuckDB: each
.duckdbfile is a database;ATTACHto add others.USE my_dbandUSE my_db.my_schemaswitch context. - SQLite: each
.dbfile is a database;ATTACH DATABASE 'other.db' AS otherto add a second one to the current connection.
FAQ #
What's the difference between a database and a schema?
Engine-dependent. Postgres / Oracle: a database contains many schemas (namespaces for tables). MySQL: database and schema are synonyms. SQL Server: a database contains schemas (default dbo). Snowflake: account → database → schema → table. BigQuery: project → dataset (no "schema" concept). The terms are confusingly overloaded.
How do I list all databases?
Postgres: \l in psql, or SELECT datname FROM pg_database. MySQL: SHOW DATABASES. SQL Server: SELECT name FROM sys.databases. Snowflake: SHOW DATABASES. BigQuery: bq ls --project_id=my-project (or list datasets via API). SQLite: each file is a database, and .databases lists attached ones.
How do I switch the current database?
MySQL / SQL Server / Snowflake / DuckDB: USE db_name. Postgres: cannot switch within a session, so open a new connection (\c db_name in psql, but it reconnects). BigQuery: no USE, so qualify all table references with project.dataset.
Why don't I have to type the schema name when I query tables?
Each engine has a "search path" or default schema concept. Postgres: search_path (default public). SQL Server: default is dbo. Snowflake: USE SCHEMA db.schema sets context. BigQuery: no defaults — always qualify. For shared queries (Slack, runbooks), always fully qualify to avoid the "works for me" problem.
How do I count tables per schema?
SELECT table_schema, COUNT(*) FROM information_schema.tables WHERE table_type = 'BASE TABLE' GROUP BY table_schema ORDER BY 2 DESC. Quick orientation when joining a new project: which schemas are large vs small? Often reveals the analytics-heavy schemas (marts, analytics) vs raw data (raw, staging).
What's the difference between Postgres schemas and MySQL databases?
Conceptually the same: a namespace for tables. Postgres has both databases (separate connection contexts) and schemas (namespaces within a database). MySQL collapses them into one concept (database and schema are synonyms). Many MySQL "databases" map to what would be Postgres schemas in a single database.
Default schema is the silent source of "table not found" errors. SELECT FROM users on Postgres only checks schemas in your search_path — usually just public. On Snowflake or BigQuery, an unqualified table name is very* dependent on session context. When sharing a query (in a Slack message, a runbook, a stored procedure), always fully qualify: analytics.public.users is unambiguous; users is a guess. The same query that works at your terminal may break in someone else's session.