Northwind Database Diagram
Northwind Traders is Microsoft's classic sample database - a food importer/exporter used in tutorials for decades - ported here to PostgreSQL. Customers place orders handled by employees; orders contain order_details lines referencing products; products come from suppliers and belong to categories; employees report to other employees and cover territories through a join table. Fourteen tables are mapped above. The detail that makes Northwind a great teaching schema: order_details uses a composite primary key of (order_id, product_id), and employees has a self-referencing reports_to foreign key - the two patterns every ER diagram course teaches.
Last updated: 2026-09-27
Tables in the Northwind schema
| Column | Type | Nullable | Key |
|---|---|---|---|
| categories | |||
| category_id | smallint | No | PK |
| category_name | character varying(15) | No | - |
| description | text | Yes | - |
| picture | bytea | Yes | - |
| customer_customer_demo | |||
| customer_id | character varying(5) | No | PK |
| customer_type_id | character varying(5) | No | PK |
| customer_demographics | |||
| customer_type_id | character varying(5) | No | PK |
| customer_desc | text | Yes | - |
| customers | |||
| customer_id | character varying(5) | No | PK |
| company_name | character varying(40) | No | - |
| contact_name | character varying(30) | Yes | - |
| contact_title | character varying(30) | Yes | - |
| address | character varying(60) | Yes | - |
| city | character varying(15) | Yes | - |
| region | character varying(15) | Yes | - |
| postal_code | character varying(10) | Yes | - |
| country | character varying(15) | Yes | - |
| phone | character varying(24) | Yes | - |
| fax | character varying(24) | Yes | - |
| employees | |||
| employee_id | smallint | No | PK |
| last_name | character varying(20) | No | - |
| first_name | character varying(10) | No | - |
| title | character varying(30) | Yes | - |
| title_of_courtesy | character varying(25) | Yes | - |
| birth_date | date | Yes | - |
| hire_date | date | Yes | - |
| address | character varying(60) | Yes | - |
| city | character varying(15) | Yes | - |
| region | character varying(15) | Yes | - |
| postal_code | character varying(10) | Yes | - |
| country | character varying(15) | Yes | - |
| home_phone | character varying(24) | Yes | - |
| extension | character varying(4) | Yes | - |
| photo | bytea | Yes | - |
| notes | text | Yes | - |
| reports_to | smallint | Yes | - |
| photo_path | character varying(255) | Yes | - |
| employee_territories | |||
| employee_id | smallint | No | PK |
| territory_id | character varying(20) | No | PK |
| order_details | |||
| order_id | smallint | No | PK |
| product_id | smallint | No | PK |
| unit_price | real | No | - |
| quantity | smallint | No | - |
| discount | real | No | - |
| orders | |||
| order_id | smallint | No | PK |
| customer_id | character varying(5) | Yes | - |
| employee_id | smallint | Yes | - |
| order_date | date | Yes | - |
| required_date | date | Yes | - |
| shipped_date | date | Yes | - |
| ship_via | smallint | Yes | - |
| freight | real | Yes | - |
| ship_name | character varying(40) | Yes | - |
| ship_address | character varying(60) | Yes | - |
| ship_city | character varying(15) | Yes | - |
| ship_region | character varying(15) | Yes | - |
| ship_postal_code | character varying(10) | Yes | - |
| ship_country | character varying(15) | Yes | - |
| products | |||
| product_id | smallint | No | PK |
| product_name | character varying(40) | No | - |
| supplier_id | smallint | Yes | - |
| category_id | smallint | Yes | - |
| quantity_per_unit | character varying(20) | Yes | - |
| unit_price | real | Yes | - |
| units_in_stock | smallint | Yes | - |
| units_on_order | smallint | Yes | - |
| reorder_level | smallint | Yes | - |
| discontinued | integer | No | - |
| region | |||
| region_id | smallint | No | PK |
| region_description | character varying(60) | No | - |
| shippers | |||
| shipper_id | smallint | No | PK |
| company_name | character varying(40) | No | - |
| phone | character varying(24) | Yes | - |
| suppliers | |||
| supplier_id | smallint | No | PK |
| company_name | character varying(40) | No | - |
| contact_name | character varying(30) | Yes | - |
| contact_title | character varying(30) | Yes | - |
| address | character varying(60) | Yes | - |
| city | character varying(15) | Yes | - |
| region | character varying(15) | Yes | - |
| postal_code | character varying(10) | Yes | - |
| country | character varying(15) | Yes | - |
| phone | character varying(24) | Yes | - |
| fax | character varying(24) | Yes | - |
| homepage | text | Yes | - |
| territories | |||
| territory_id | character varying(20) | No | PK |
| territory_description | character varying(60) | No | - |
| region_id | smallint | No | - |
| us_states | |||
| state_id | smallint | No | PK |
| state_name | character varying(100) | Yes | - |
| state_abbr | character varying(2) | Yes | - |
| state_region | character varying(50) | Yes | - |
Frequently asked questions
What tables are in the Northwind database?
Northwind has 14 tables: categories, customers, customer_demographics, customer_customer_demo, employees, employee_territories, territories, region, orders, order_details, products, suppliers, shippers, and us_states.
How are orders and products linked in Northwind?
Through the order_details join table, which has a composite primary key of (order_id, product_id) plus quantity, unit price, and discount. One order has many lines; each line references exactly one product.
How does Northwind model employee reporting lines?
With a self-referencing foreign key: employees.reports_to points at employees.employee_id, so each employee row links to their manager's row. Territories add a second dimension via the employee_territories join table.
Explore more schemas
Visualize your own database
Paste your PostgreSQL connection string and get an interactive ER diagram of your own schema in under 10 seconds. No signup required.
Try it free →