AiTechWorlds
AiTechWorlds
Think about a physical file cabinet. There are exactly four things you can do to any record inside it: put a new one in, read one, change one, or throw one away. Everything else — searching, sorting, reporting — is a variation of reading.
Databases are no different. The four fundamental operations are Create, Read, Update, Delete — and in SQL: INSERT, SELECT, UPDATE, DELETE.
Master these four, and you can do anything with data. Every complex query, every dashboard, every report is built from these primitives.
Throughout this lesson, we'll use these tables. Here's the starting state:
books
| book_id | title | genre | copies_available | author_id |
|---|---|---|---|---|
| 1 | Clean Code | Technology | 3 | 1 |
| 2 | The Great Gatsby | Fiction | 1 | 2 |
| 3 | Sapiens | History | 2 | 3 |
members
| member_id | first_name | last_name | membership_type | |
|---|---|---|---|---|
| 1 | Alice | Nguyen | alice@email.com | premium |
| 2 | Ben | Carter | ben@email.com | standard |
INSERT INTO members (first_name, last_name, email, membership_type)
VALUES ('Clara', 'Smith', 'clara@email.com', 'student');
Result — members table after:
| member_id | first_name | last_name | membership_type | |
|---|---|---|---|---|
| 1 | Alice | Nguyen | alice@email.com | premium |
| 2 | Ben | Carter | ben@email.com | standard |
| 3 | Clara | Smith | clara@email.com | student |
INSERT INTO books (title, genre, copies_available, author_id)
VALUES
('Thinking, Fast and Slow', 'Psychology', 2, 4),
('The Pragmatic Programmer', 'Technology', 4, 5),
('Dune', 'Fiction', 1, 6);
One round trip to the database, three rows inserted. Much faster than three separate INSERT statements for bulk data.
INSERT INTO archive_loans (loan_id, book_id, member_id, return_date)
SELECT loan_id, book_id, member_id, return_date
FROM loans
WHERE return_date < '2024-01-01';
This reads from one table and writes directly into another — no application code needed to move data.
SELECT is the most-used SQL command. It never changes data — it only reads it.
SELECT * FROM books;
The * means "all columns." Fine for exploration; avoid it in production queries (brittle if columns change).
SELECT title, genre, copies_available
FROM books;
Result:
| title | genre | copies_available |
|---|---|---|
| Clean Code | Technology | 3 |
| The Great Gatsby | Fiction | 1 |
| Sapiens | History | 2 |
SELECT title, copies_available
FROM books
WHERE genre = 'Technology';
Result:
| title | copies_available |
|---|---|
| Clean Code | 3 |
SELECT title, copies_available
FROM books
ORDER BY copies_available DESC;
Result:
| title | copies_available |
|---|---|
| Clean Code | 3 |
| Sapiens | 2 |
| The Great Gatsby | 1 |
ASC (ascending, A→Z, 0→9) is the default. DESC reverses it.
-- First 2 books
SELECT title FROM books LIMIT 2;
-- Skip 2, return next 2 (page 2 of results)
SELECT title FROM books LIMIT 2 OFFSET 2;
| Operator | Example | Matches |
|---|---|---|
= | genre = 'Fiction' | Exact match |
!= or <> | genre != 'Fiction' | Not equal |
>, <, >=, <= | copies_available > 1 | Numeric/date comparison |
BETWEEN | published_year BETWEEN 2000 AND 2020 | Inclusive range |
IN | genre IN ('Fiction', 'History') | Matches any value in list |
NOT IN | genre NOT IN ('Fiction') | Excludes listed values |
LIKE | title LIKE 'The%' | Pattern match (% = any chars, _ = one char) |
IS NULL | return_date IS NULL | Column has no value |
IS NOT NULL | author_id IS NOT NULL | Column has a value |
AND | genre = 'Fiction' AND copies > 0 | Both conditions true |
OR | genre = 'Fiction' OR genre = 'History' | Either condition true |
UPDATE books
SET copies_available = 5
WHERE book_id = 1;
books before:
| book_id | title | copies_available |
|---|---|---|
| 1 | Clean Code | 3 |
| 2 | The Great Gatsby | 1 |
books after:
| book_id | title | copies_available |
|---|---|---|
| 1 | Clean Code | 5 |
| 2 | The Great Gatsby | 1 |
UPDATE members
SET membership_type = 'premium',
email = 'ben.carter@email.com'
WHERE member_id = 2;
-- Reduce all Technology books by 1 copy (someone borrowed them)
UPDATE books
SET copies_available = copies_available - 1
WHERE genre = 'Technology';
DELETE FROM members
WHERE member_id = 3;
members before:
| member_id | first_name | last_name |
|---|---|---|
| 1 | Alice | Nguyen |
| 2 | Ben | Carter |
| 3 | Clara | Smith |
members after:
| member_id | first_name | last_name |
|---|---|---|
| 1 | Alice | Nguyen |
| 2 | Ben | Carter |
DELETE FROM loans
WHERE return_date < '2023-01-01';
-- This deletes EVERY row in the table:
DELETE FROM members;
-- This updates EVERY row in the table:
UPDATE books SET copies_available = 0;
A missing WHERE on UPDATE or DELETE is one of the most common production database disasters. The DBMS executes exactly what you wrote.
Before running any UPDATE or DELETE in production, run the equivalent SELECT first.
-- Step 1: See what you're about to change
SELECT * FROM loans WHERE return_date < '2023-01-01';
-- Step 2: If the output looks right, delete it
DELETE FROM loans WHERE return_date < '2023-01-01';
This takes 10 extra seconds and has saved countless databases. The SELECT shows you exactly which rows the WHERE clause matches before any data is changed.
Wrap critical operations in a transaction for additional safety:
BEGIN;
DELETE FROM loans WHERE return_date < '2023-01-01';
-- Verify the deletion before committing
SELECT COUNT(*) FROM loans;
-- If everything looks right:
COMMIT;
-- If something went wrong:
-- ROLLBACK;
| Command | Reads Data? | Writes Data? | Can Be Targeted with WHERE? | Rolls Back? |
|---|---|---|---|---|
SELECT | Yes | No | Yes (filters rows) | N/A |
INSERT | No | Yes (adds rows) | No | Yes |
UPDATE | No | Yes (changes rows) | Yes | Yes |
DELETE | No | Yes (removes rows) | Yes | Yes |
CRUD operations are simple. The discipline around using them safely is what matters.
Next lesson: Joins — combining data from multiple tables to answer real-world questions.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises