Lesson 1 / 4
🗄️ Introduction to SQL and Databases
What SQL is, why it's needed, what a database looks like, and the difference between SQL and Excel.
🔍 What is SQL?
definition
SQL = Structured Query Language — a built-in query language.
Unlike languages like Python or Java that are "general-purpose languages", SQL is A domain-specific language (Domain-Specific) which was created solely for working with data.
SQL's syntax resembles Simple English — commands like
Unlike languages like Python or Java that are "general-purpose languages", SQL is A domain-specific language (Domain-Specific) which was created solely for working with data.
SQL's syntax resembles Simple English — commands like
SELECT, FROM, WHERE make the code readable and understandable.
History: SQL was developed in the 1970s at IBM labs and was originally called SEQUEL. Since then it has remained the leading language in the data world — for over 50 years!
❓ Why SQL at all instead of Excel?
3 key reasons
1. Big Data — massive data volumes
When Excel starts to "stutter" (around a million rows) — SQL is just getting warmed up. SQL processes billions of rows in a few seconds.
2. "The single source of truth" — a central database
Unlike files that circulate over email and get changed, SQL maintains a single central database, prevents mistakes and preserves valid logical relationships.
3. Surgical extraction
Excel loads the entire file into memory. SQL retrieves only the specific data you need — saves memory and shortens run times.
When Excel starts to "stutter" (around a million rows) — SQL is just getting warmed up. SQL processes billions of rows in a few seconds.
2. "The single source of truth" — a central database
Unlike files that circulate over email and get changed, SQL maintains a single central database, prevents mistakes and preserves valid logical relationships.
3. Surgical extraction
Excel loads the entire file into memory. SQL retrieves only the specific data you need — saves memory and shortens run times.
| criterion | Excel | SQL |
|---|---|---|
| Number of rows | Up to ~1M rows | Billions of rows |
| speed | Slow with large files | Very fast |
| Data sharing | Files floating around | One central database |
| security | Anyone can edit | Permissions and control |
| Performing calculations | Convenient for a regular user | Powerful and precise |
🗃️ What does a database look like?
Database structure
A database is made up ofTables (Tables). Each table contains Columns (Columns) FRows (Rows).
Imagine a bunch of Excel sheets linked to each other — that's what a database looks like.
Imagine a bunch of Excel sheets linked to each other — that's what a database looks like.
1
Database — the overall database (e.g. Northwind)
2
Tables — tables inside the database (for example: customers, orders, products)
3
Columns — columns in a table (for example: id, first_name, city)
4
Rows — data rows (for example: a specific customer's details)
🔑 Keys and relationships
Primary Key — primary key
A column that identifies each row unique. There can't be two identical values. There can't be a NULL.
example: column
example: column
id In the customers table — every customer has their own unique number.
Foreign Key — foreign key
A column in one table that points toPrimary Key in another table. Creates the relationship between the tables.
example: column
example: column
customer_id in the orders table points toid In the customers table.
tip: The relationship between a primary key and a foreign key is the foundation of the JOIN command — it is how you connect information from different tables.
🏪 The course database — Northwind
What is Northwind?
A classic database that simulates Trading company. Includes customers, orders, products, suppliers and employees. Widely used for learning SQL for decades.
The main tables
customers — Customers | orders — Orders | order_details — order detailsproducts — Products | employees — Employees | suppliers — Suppliers | shippers — shipping companies
Lesson 2 / 4
📝 String functions (String Functions)
Cleaning, extraction, formatting and validation of text data. 4 main action categories.
🧹 Category 1: data cleaning (Cleaning)
TRIM / LTRIM / RTRIM
Removes extra spaces from the string.
TRIM — from both sides | LTRIM — left side only | RTRIM — right side only
SQL
SELECT TRIM(' Hello World ') AS clean_text; -- result: 'Hello world' SELECT company, TRIM(company) AS clean_company FROM customers;
REPLACE
Replaces one substring with another.
REPLACE(column, 'what to replace', 'with what')
SQL
-- Removing dashes from phone numbers SELECT REPLACE(business_phone, '-', '') AS clean_phone FROM customers; -- replacing UK with United Kingdom SELECT REPLACE(country_region, 'UK', 'United Kingdom') FROM customers;
✂️ Category 2: Data Extraction
LEFT / RIGHT
LEFT(column, N) — N characters from the startRIGHT(column, N) — N characters from the end
SQL
-- first 3 letters of the company name SELECT company, LEFT(company, 3) AS short_code FROM customers; -- last 4 digits of the phone SELECT RIGHT(business_phone, 4) AS phone_end FROM customers;
SUBSTRING
SUBSTRING(column, start, length) — extracting from a specific position.important: The position starts at 1 (not 0!).
SQL
-- 5 characters starting from character 2 SELECT SUBSTRING(product_name, 2, 5) AS middle_text FROM products;
LENGTH and INSTR
LENGTH(column) — returns the string's length in number of charactersINSTR(column, 'char') — returns the position of a substring
SQL
SELECT email_address, LENGTH(email_address) AS email_length, INSTR(email_address, '@') AS at_position FROM employees;
🎨 Category 3: reformatting (Formatting)
CONCAT and CONCAT_WS
CONCAT(a, b, c) — concatenates strings. If one of the values is NULL — the result is NULL.CONCAT_WS(separator, a, b, c) — joins with a fixed delimiter and skips NULL automatically.
SQL
-- full address with commas (skips NULL) SELECT CONCAT_WS(', ', city, state_province, zip_postal_code) AS full_address FROM customers; -- price with a $ sign SELECT CONCAT('$', ROUND(list_price, 2)) AS formatted_price FROM products;
✅ Category 4: Validity and consistency (Standardization)
UPPER / LOWER
UPPER(column) — turns all the text into uppercase lettersLOWER(column) — turns all the text into lowercase lettersUseful for normalizing data before comparison.
SQL
SELECT UPPER(company) AS company_caps FROM suppliers; SELECT LOWER(email_address) AS standard_email FROM employees;
note: UPPER/LOWER change the Display only — they don't save the change to the table. For a permanent change you need UPDATE.
Lesson 3 / 4
🔎 WHERE — filtering data
Filtering rows by conditions. The most essential tool for real queries — includes AND/OR, IN, BETWEEN, LIKE, and IS NULL.
📍 WHERE basics
syntax
WHERE arrives After FROM and filters rows by a condition.Comparison operators:
= != < > <= >=
SQL
-- products priced above 50 SELECT product_name, list_price FROM products WHERE list_price > 50; -- Employees who are not Sales Representative SELECT first_name, job_title FROM employees WHERE job_title != 'Sales Representative';
🔗 AND / OR — Multiple Conditions
the difference
AND — second The conditions must be metOR — At least one Of the conditions must holdParentheses set precedence:
WHERE (a OR b) AND c
SQL
-- AND: customers from USA and New York SELECT * FROM customers WHERE country_region = 'USA' AND city = 'New York'; -- OR: products from Beverages or Condiments SELECT product_name FROM products WHERE category = 'Beverages' OR category = 'Condiments';
📋 IN — list of values
What is IN?
IN It's a convenient shorthand for multiple OR conditions. More readable and shorter.WHERE city IN ('Tel Aviv', 'Jerusalem', 'Haifa')
SQL
-- Suppliers from 3 cities (shorthand for OR) SELECT company, city FROM suppliers WHERE city IN ('Tokyo', 'London', 'New York'); -- NOT IN: not from these cities SELECT * FROM customers WHERE country_region NOT IN ('USA', 'UK');
📏 BETWEEN — a range of values
Important to know
BETWEEN x AND y — includes both endpoints (x and y themselves).equivalent to:
WHERE col >= x AND col <= y
SQL
-- Orders with shipping fees between 20 and 50 SELECT id, shipping_fee FROM orders WHERE shipping_fee BETWEEN 20 AND 50;
🔍 LIKE — pattern search
Wildcard characters
% — any number of characters (even zero)_ — exactly one character'%gmail%' — contains gmail | 'j%' — starts with j | '%@gmail.com' — ends with @gmail.com
SQL
-- emails ending in northwindtraders.com SELECT * FROM employees WHERE email_address LIKE '%northwindtraders.com'; -- names that start with A SELECT first_name FROM employees WHERE first_name LIKE 'A%';
🚫 IS NULL / IS NOT NULL
NULL — a missing value
NULL is a value Missing / unknown — not zero, not empty!
Cannot use
Cannot use
= NULL — must IS NULL.
SQL
-- orders not yet shipped SELECT id, order_date FROM orders WHERE shipped_date IS NULL; -- Customers with a website SELECT company, web_page FROM customers WHERE web_page IS NOT NULL;
Common error!
WHERE shipped_date = NULL — this doesn't work in SQL! Always useIS NULL.Lesson 4 / 4
📦 GROUP BY and aggregation
Grouping rows and computing statistics — COUNT, SUM, AVG, MIN, MAX. Includes HAVING, ROLLUP and UNION.
📊 Aggregate functions
The main functions
COUNT(*) — counts rows | COUNT(column) — counts non-NULL valuesSUM(column) — computes a sumAVG(column) — computes an averageMIN(column) — the lowest valueMAX(column) — the highest value
SQL
-- statistics on the products table SELECT COUNT(*) AS total_products, AVG(list_price) AS avg_price, MIN(list_price) AS min_price, MAX(list_price) AS max_price FROM products;
🗂️ GROUP BY — grouping into groups
The important rule
Every column in SELECT that isn't an aggregate function must to be in the GROUP BY.
GROUP BY splits the table into groups and computes an aggregate for each group.
GROUP BY splits the table into groups and computes an aggregate for each group.
SQL
-- how many products are in each category? SELECT category, COUNT(*) AS product_count FROM products GROUP BY category; -- average price per category SELECT category, AVG(list_price) AS avg_price FROM products GROUP BY category ORDER BY avg_price DESC;
🔍 HAVING — Filtering After Grouping
WHERE vs. HAVING
WHERE — filters rows before the groupingHAVING — filters groups after the groupingrule: You can't use aggregate functions (COUNT, SUM…) in WHERE. That's why you need HAVING.
SQL
-- Categories with more than 5 products SELECT category, COUNT(*) AS cnt FROM products GROUP BY category HAVING COUNT(*) > 5; -- WHERE (before) + HAVING (after) SELECT category, AVG(list_price) AS avg FROM products WHERE list_price > 10 -- filter before grouping GROUP BY category HAVING AVG(list_price) > 30; -- filter after grouping
Trick to remember: WHERE → before GROUP BY (on rows). HAVING → after GROUP BY (on groups).
📈 ROLLUP — grand summary
What is ROLLUP?
GROUP BY column WITH ROLLUP — adds a grand total row at the end of the results.The last row will contain NULL in the grouping column and a grand total.
SQL
-- count by category + total SELECT COALESCE(category, '--- Total ---') AS category, COUNT(*) AS total FROM products GROUP BY category WITH ROLLUP;
🔀 UNION — combining results
UNION vs UNION ALL
UNION — combines the results of two queries and removes duplicatesUNION ALL — merges and keeps duplicates (faster)condition: Both queries must return the same number of columns with compatible data types.
SQL
-- a combined list of cities from customers and suppliers SELECT city, 'customer' AS type FROM customers UNION SELECT city, 'supplier' AS type FROM suppliers ORDER BY city;
📋 SQL execution order — important to know!
1
FROM — which table to pull from
2
WHERE — filtering rows
3
GROUP BY — grouping into groups
4
HAVING — filtering groups
5
SELECT — choosing columns to display
6
ORDER BY — sorting the results
7
LIMIT — limiting the number of rows
The order that we we write SQL differs from the order the DB promotion it. This is why you can't use an Alias from SELECT inside WHERE.