Almost every application you touch — your bank, your playlist, the form you just filled in — is a thin skin over a database. The buttons and pages exist to collect and show information; the database is where that information actually lives, quietly remembering it between visits.
SQL (Structured Query Language) is how you ask a database questions, and it has done that job for fifty years across Postgres, MySQL, SQLite, BigQuery, and Oracle. The query you write against the toy database in this lesson would run, almost unchanged, against a billion-row warehouse.
That makes SQL the most portable skill in this entire course. Analysts, backend engineers, data scientists, and product managers all reach for it. You learn the ideas once and carry them between companies, languages, and decades.
flowchart LR
APP["An application"] --> DB[("Database")]
DB --> T1["departments"]
DB --> T2["employees"]
DB --> T3["projects"]
style DB fill:#0e7490,color:#fff
style APP fill:#3776ab,color:#fff
The relational mental model
A relational database stores information in tables — grids of rows and columns, much like a spreadsheet, but with rules that keep the data trustworthy. Each table holds one kind of thing, and each row in that table describes one individual.
The database for this course has three tables:
departments—id,name,cityemployees—id,name,department_id,role,salary,hired_onprojects—id,name,department_id,status,budget
A row is one record — Ada Nilsen, a specific engineer. A column is one attribute shared by every record — salary, the amount each person earns. Keeping those two words straight is what makes every error message ahead of you readable.
erDiagram
DEPARTMENTS ||--o{ EMPLOYEES : "has"
DEPARTMENTS ||--o{ PROJECTS : "owns"
DEPARTMENTS {
int id
text name
text city
}
EMPLOYEES {
int id
text name
int department_id
text role
int salary
}
PROJECTS {
int id
text name
int department_id
text status
}
What makes it 'relational'
The clever part is the links between tables. Notice that employees has a department_id column, and so does projects. Those are not real attributes of a person or a project — they are pointers. An employee whose department_id is 1 belongs to Engineering, because 1 is the id of the Engineering row in departments.
A pointer like this is called a foreign key, and it is the reason the model is named relational. The data is split across tables so that each fact is stored exactly once, and the foreign keys let a query follow the pointers and stitch the pieces back together for a single answer. One employee who is also a marketer no longer needs two copies of the department name; the link does the work.
SQL is declarative — you say what, not how
Most programming you have done tells the computer how to do something, one step at a time. SQL is different: you describe the result you want, and the database works out how to produce it. You never tell it to loop over rows or walk an index; you state which table, which rows, and which columns, and you trust the engine to fetch efficiently.
That is why a short SQL query can answer a question that would take many lines of Python. You trade fine-grained control for leverage — and for the kind of question databases exist to answer, leverage is exactly what you want.
flowchart LR
Q["You: name and salary<br/>of the top earners"] --> S["SQL describes<br/>the result"]
S --> E[("Database engine<br/>decides the how")]
E --> R["A new table<br/>of answers"]
style Q fill:#3776ab,color:#fff
style R fill:#0e7490,color:#fff
SELECT name, city FROM departments;
Choosing columns with SELECT
Read that query aloud as "select the name and city columns from the departments table." The list between SELECT and FROM is called projection — you pick which columns to show and in what order, and the rest are hidden. Want a different view of the same rows? Change only the column list and run it again.
If you want every column and would rather not type them all, write SELECT *. The star means "all of them." It is excellent while exploring an unfamiliar table, but for real queries you should name the columns you mean, so the result stays predictable even if the table grows new columns later on.
SELECT name, salary FROM employees;
SELECT * FROM projects;
Which table would you query to find out how much someone earns?
The salary column lives on the employees table. (There is no salaries table — a common assumption worth checking before you write a query.)
In the employees table, what does a single row represent?
Each row is a single record — here, one member of staff. Columns describe that person; the table as a whole holds everyone.
List the name and role of every employee in the company.
SELECT name, role FROM employees ;
You want two columns:
nameandrole.They both live in the
employeestable.
SELECT name, role FROM employees;
List the name and budget of every project.
SELECT name, budget FROM ;
The columns you want are
nameandbudget.Projects live in the
projectstable.
SELECT name, budget FROM projects;
Show every column of the departments table — id, name, and city.
SELECT FROM departments ;
SELECT *means every column.Fill in the star between SELECT and FROM.
SELECT * FROM departments;
Recap
- A database holds many tables; each table stores one kind of fact as rows (records) and columns (attributes).
- A foreign key like
department_idis a pointer linking a row in one table to a row in another — the 'relational' in relational database. - SQL is declarative: you state the shape of the answer, not the steps to reach it.
SELECTchooses columns (projection);SELECT *chooses all of them, and the answer comes back as a new table.
Next you will open up the schema and see exactly how those tables, columns, and keys fit together — the relational model that the rest of the course stands on.