21 KiB
note type, date, done, link
| note type | date | done | link | |||
|---|---|---|---|---|---|---|
|
2026-06-03 | https://app.pluralsight.com/ilx/video-courses/sql-joins-constraints-normalization-subqueries/course-overview |
Common Aggregate Functions
| title | cost | duration |
|---|---|---|
| Gone with the wind | 390000 | 220 |
| Frankenstein | 3000000 | 50 |
| Creature from the black lagoon | 500000 | 79 |
| NULL | 100 | 10 |
1. COUNT()
Count all rows
SELECT COUNT(*) FROM Movies;
Output:
4
- Counts all rows, including rows where columns are
NULL.
Count non-NULL values in a column
SELECT COUNT(title) FROM Movies;
Output:
3
NULLtitle is not counted.
2. MIN()
SELECT MIN(cost) FROM Movies;
Output:
100
- Returns the smallest value in the column.
3. MAX()
SELECT MAX(cost) FROM Movies;
Output:
3000000
- Returns the largest value.
4. SUM()
SELECT SUM(cost) FROM Movies;
Output:
3890100
Calculation:
390000 + 3000000 + 500000 + 100 = 3890100
- Adds all values in the column.
- Ignores
NULLvalues (none incosthere).
5. AVG()
SELECT AVG(cost) FROM Movies;
Output:
972525
Calculation:
3890100 / 4 = 972525
- Computes the average of all values.
Using Multiple Aggregates
SELECT
COUNT(*) AS total_movies,
MIN(cost) AS cheapest,
MAX(cost) AS most_expensive,
SUM(cost) AS total_cost,
AVG(cost) AS average_cost
FROM Movies;
Output:
total_movies | cheapest | most_expensive | total_cost | average_cost
4 | 100 | 3000000 | 3890100 | 972525
Filtering Aggregates
| title | cost | duration | genre |
|---|---|---|---|
| Gone with the wind | 390000 | 220 | Drama |
| Frankenstein | 3000000 | 50 | Horror |
| Creature from the black lagoon | 500000 | 79 | Horror |
| Casablanca | 1000000 | 102 | Drama |
| Toy Story | 2000000 | 81 | Family |
| NULL | 100 | 10 | Horror |
GROUP BY
GROUP BY groups rows so aggregates are calculated per group rather than across the whole table.
SELECT genre, SUM(cost) AS total_cost
FROM Movies
GROUP BY genre;
Output:
genre | total_cost
Drama | 1390000
Horror | 3500100
Family | 2000000
SELECT genre, AVG(duration) AS avg_duration
FROM Movies
GROUP BY genre;
Output:
genre | avg_duration
Drama | 161
Horror | 46.33
Family | 81
WHERE (filtering rows before aggregation)
WHERE filters rows before grouping and aggregation.
SELECT genre, COUNT(*) AS num_movies
FROM Movies
WHERE duration > 60
GROUP BY genre;
Output:
genre | num_movies
Drama | 2
Horror | 1
Family | 1
Explanation:
- The row with duration = 10 is excluded before grouping.
HAVING (filtering groups after aggregation)
HAVING filters results after aggregation.
SELECT genre, SUM(cost) AS total_cost
FROM Movies
GROUP BY genre
HAVING SUM(cost) >= 2000000;
Output:
genre | total_cost
Horror | 3500100
Family | 2000000 -- note: included only if >= was used
If strictly > 2000000, only:
Horror | 3500100
SELECT genre, COUNT(*) AS num_movies
FROM Movies
GROUP BY genre
HAVING COUNT(*) > 2;
Output:
genre | num_movies
Horror | 3
Combined Example
SELECT genre, AVG(cost) AS avg_cost
FROM Movies
WHERE duration > 60
GROUP BY genre
HAVING AVG(cost) > 1000000;
Steps:
- WHERE filters rows (duration > 60)
- GROUP BY groups remaining data
- HAVING filters grouped results
Output:
genre | avg_cost
Family | 2000000
Constraints
Example Table (Promotions)
CREATE TABLE Promotions (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
category VARCHAR(50) NOT NULL,
CONSTRAINT unique_name_category
UNIQUE (name, category)
);
Purpose of Constraints
- Prevent invalid or unwanted data
- Enforce rules on table columns
- Improve data integrity
NOT NULL
- Prevents a column from storing
NULLvalues - Use when a value is required
name VARCHAR(100) NOT NULL
UNIQUE
- Ensures all values in a column are distinct
- Prevents duplicate entries
name VARCHAR(100) UNIQUE
Composite UNIQUE
- Enforces uniqueness across multiple columns
UNIQUE (name, category)
- Same name allowed if category differs
- Same category allowed if name differs
- Duplicate combinations are not allowed
Multiple Constraints on a Column
- You can combine constraints:
name VARCHAR(100) NOT NULL UNIQUE
Named Constraints
- Assign custom names for easier maintenance
CONSTRAINT unique_name UNIQUE (name)
Column vs Table Constraints
- Column constraint: defined inline
- Table constraint: defined separately
Both work the same, except:
NOT NULLmust be defined at the column level
PRIMARY KEY
- Uniquely identifies each row
- Automatically enforces:
- NOT NULL
- UNIQUE
id INT PRIMARY KEY
Key Rules
- Only one primary key per table
- Can consist of one or multiple columns
PRIMARY KEY vs UNIQUE + NOT NULL
- Both enforce uniqueness and no nulls
- Difference:
- PRIMARY KEY: only one per table
- UNIQUE + NOT NULL: can use multiple columns
Value Constraints (Foreign Key & CHECK)
Example Tables (Movies + Promotions)
CREATE TABLE Movies (
id INT PRIMARY KEY,
title VARCHAR(100) NOT NULL,
duration INT CHECK (duration > 0)
);
CREATE TABLE Promotions (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
category VARCHAR(50) NOT NULL,
movie_id INT,
CONSTRAINT fk_movie
FOREIGN KEY (movie_id)
REFERENCES Movies(id),
CONSTRAINT unique_name_category
UNIQUE (name, category)
);
Foreign Key (FK)
Definition
- A foreign key is a column in one table that references a primary key in another table
- Used to link tables and avoid duplicating data
movie_id INT REFERENCES movies(id)
This is the same as:
movie_id INT REFERENCES movies
Naming Convention
- Format:
referencedTable_singular + _id
Examples:
movie_id→ references Movies(id)user_id→ references Users(id)
Why Use Foreign Keys
- Prevents invalid references
- Ensures data integrity
- Avoids duplicating data across tables
Behaviour Without FK
- You can insert invalid data:
movie_id = 999 -- even if it doesn't exist
- Creates bad data
Behaviour With FK
- Database blocks invalid inserts
INSERT INTO Promotions (id, name, category, movie_id)
VALUES (1, 'Half Off', 'Discount', 999); -- fails
- Error: violates foreign key constraint
Table Creation Order Rule
- The referenced table must be created first
CREATE TABLE Movies (...)
CREATE TABLE Promotions (... REFERENCES Movies)
Table Constraint Version
FOREIGN KEY (movie_id) REFERENCES movies
Orphan Records
Definition
- A row that references data that no longer exists
Example:
- Movie deleted
- Promotion still points to that movie_id
How FK Prevents Orphans
- Prevents deleting parent rows if children exist
DELETE FROM Movies WHERE id = 6; -- fails if Promotions reference it
- You must:
- Delete child rows first
- Then delete parent
Dropping Tables
- Cannot drop a table if another table depends on it
DROP TABLE Movies; -- fails if Promotions references it
- Must drop dependent tables first
CHECK Constraint
Definition
- Validates column values using a condition
salary int CHECK (salary > 500)
Purpose of CHECK
- Prevent logically invalid data
Example:
- Duration cannot be negative
Behaviour
INSERT INTO Movies (id, title, duration)
VALUES (1, 'Test Movie', -10); -- fails
Example Inserts
Valid Movie
INSERT INTO Movies (id, title, duration)
VALUES (1, 'Gone With the Wind', 240);
Valid Promotion
INSERT INTO Promotions (id, name, category, movie_id)
VALUES (1, 'Matinee', 'Discount', 1);
Fails (invalid foreign key)
INSERT INTO Promotions (id, name, category, movie_id)
VALUES (2, 'Half Off', 'Discount', 999);
Fails (negative duration)
INSERT INTO Movies (id, title, duration)
VALUES (2, 'Bad Movie', -10);
SQL Relationships & Normalization (Level 3 Notes)
Overview
- Focus: Database relationships and normalization to improve data integrity and flexibility.
- Example context: A Movies application where each movie can have multiple genres.
Problem with Current Design
- Storing multiple genres in one column (e.g.,
"Adventure, Fantasy") causes issues:- Hard to query (e.g., finding all Adventure movies).
- Difficult to update individual values.
- Violates normalization rules.
Example Issue
SELECT * FROM Movies WHERE genre = 'Adventure';
- Returns movies with only
"Adventure", but misses movies like"Adventure, Fantasy".
Normalization Basics
First Normal Form (1NF)
- Rule: No repeating groups in a column.
- Each field should contain a single value (atomic).
Fix
Split rows so each genre is separate:
| title | genre | duration |
|---|---|---|
| Peter Pan | Adventure | 120 |
| Peter Pan | Fantasy | 120 |
- Eliminates multi-value columns.
- Still problematic: duplicate movie data.
Second Normal Form (2NF)
- Rule: No redundancy (no repeated unnecessary data).
- Each piece of information should be stored once.
Problem in 1NF Table
- Movie details (e.g., duration) are duplicated across rows.
Solution: Table Decomposition
Step 1: Create a Movies Table
- Store unique movies only.
| id | title | duration |
|---|---|---|
| 1 | Don Juan | 110 |
| 2 | Peter Pan | 120 |
Step 2: Create a Genres Table
- Store each genre once.
| id | name |
|---|---|
| 1 | Romance |
| 2 | Adventure |
| 3 | Fantasy |
Step 3: Create a Join Table (Many-to-Many)
- Name convention:
movies_genres - Purpose: Link movies to genres.
| movie_id | genre_id |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 2 | 3 |
movie_id→ referencesMovies.idgenre_id→ referencesGenres.id- Both are foreign keys
Benefits of This Design
- No duplication (meets 2NF).
- Easy updates:
- Change movie duration in one place.
- Add/remove genres without affecting other data.
- Scalable for complex relationships.
Querying the Data
Step-by-step (manual approach)
- Get movie ID:
SELECT id FROM Movies WHERE title = 'Peter Pan';
- Get associated genre IDs:
SELECT genre_id FROM movies_genres WHERE movie_id = 2;
- Get genre names:
SELECT name FROM Genres WHERE id IN (2, 3);
Simplified Query Using IN
SELECT name FROM Genres WHERE id IN (2, 3);
Example Operation
Add a new genre to a movie
Add "Fantasy" to "Robin Hood":
INSERT INTO movies_genres (movie_id, genre_id)
VALUES (4, 3);
Key Takeaways
- Avoid storing multiple values in a single column.
- Use normalization to:
- Eliminate redundancy
- Improve data consistency
- Use join tables for many-to-many relationships.
- Trade-off: Queries become slightly more complex, but data becomes more robust and flexible.
Database Relationships
Overview
There are three fundamental relationship types between tables:
- One-to-One (1:1)
- One-to-Many (1:N)
- Many-to-Many (N:N)
1. One-to-Many (1:N)
Definition
- A single row in Table A can relate to multiple rows in Table B.
- A row in Table B relates to only one row in Table A.
Key Implementation
- Add a foreign key in the "many" table.
Example
- Movies → Promotions
- One movie can have many promotions.
- Each promotion belongs to one movie.
Movies (id) ← Promotions (movie_id)
Diagram Representation
1on the "one" side*on the "many" side
2. Many-to-Many (N:N)
Definition
- Multiple rows in Table A can relate to multiple rows in Table B.
Key Implementation
- Requires a join table (junction table) that holds foreign keys from both tables.
Example
- Movies ↔ Genres
- A movie can have many genres.
- A genre can belong to many movies.
Movies_Genres
- movie_id
- genre_id
Diagram Representation
*on both sides- Join table is typically implied (not always shown explicitly)
3. One-to-One (1:1)
Definition
- A row in Table A relates to exactly one row in Table B.
Use Case
- Used to split large or complex tables into smaller ones.
Example
- Customers ↔ Addresses
- Each customer has one address.
- Each address belongs to one customer.
Customers (address_id) → Addresses (id)
Diagram Representation
1on both sides
Relationship Identification Examples
Example 1: Movies & Reviews
- One movie can have many reviews.
- Each review belongs to one movie.
Relationship: One-to-Many
Movies (id) ← Reviews (movie_id)
Example 2: Movies & Promotions
- A promotion can apply to many movies.
- A movie can have many promotions.
Relationship: Many-to-Many
Movies_Promotions
- movie_id
- promotion_id
Summary
| Relationship Type | Key Idea | Implementation |
|---|---|---|
| One-to-One | 1 row ↔ 1 row | Foreign key on one side |
| One-to-Many | 1 row → many rows | Foreign key in "many" table |
| Many-to-Many | Many ↔ many | Join table with two FKs |
- Always identify how entities relate from a business perspective, not just technically.
- Use:
- Foreign keys for 1:1 and 1:N
- Join tables for N:N
- Diagrams use:
1= single*= many
SQL INNER JOINs (Level 4 Notes)
Overview
- INNER JOIN is used to combine rows from two (or more) tables based on a related column.
- It returns only the matching records between the tables (the overlapping part).
- Common use case: retrieving related data in a single query instead of multiple queries.
Key Concepts
1. Problem Without JOIN
- To get reviews and corresponding movie titles:
- Query reviews: SELECT review, movie_id FROM Reviews;
- Use returned
movie_ids to query movies: SELECT title FROM Movies WHERE id IN (1, 3, 4);
- This requires multiple queries, which is inefficient.
2. INNER JOIN Syntax
SELECT *
FROM Movies
INNER JOIN Reviews
ON Movies.id = Reviews.movie_id;
Explanation:
INNER JOIN Reviews: specifies the table to join.ON Movies.id = Reviews.movie_id: defines how rows relate:Movies.id= primary keyReviews.movie_id= foreign key
3. Result Behaviour
- Only rows with matching keys in both tables are returned.
- Examples:
- Movies without reviews → excluded
- Reviews without movies → excluded
- A movie with multiple reviews → appears multiple times
Example:
- Movie "Don Juan" with 3 reviews → appears 3 times.
- Movie "Peter Pan" with no reviews → does not appear.
4. Order of Tables
Both queries return the same result:
FROM Movies INNER JOIN Reviews
or
FROM Reviews INNER JOIN Movies
- Because INNER JOIN returns only matching data, order doesn't change the result.
5. Selecting Specific Columns
Instead of retrieving all columns (SELECT *), specify only what you need:
SELECT Movies.title, Reviews.review
FROM Movies
INNER JOIN Reviews
ON Movies.id = Reviews.movie_id;
- Important: Prefix columns with table names to avoid ambiguity.
6. INNER JOIN Across Multiple Tables
You can join more than two tables in a single query.
Example: Get movie title and genres
SELECT Movies.title, Genres.name
FROM Movies
INNER JOIN Movies_Genres
ON Movies.id = Movies_Genres.movie_id
INNER JOIN Genres
ON Movies_Genres.genre_id = Genres.id
WHERE Movies.title = 'Peter Pan';
How it works:
- Join Movies → Movies_Genres via
movie_id - Join Movies_Genres → Genres via
genre_id - Filter for
"Peter Pan"
Visual Understanding
- Think of INNER JOIN like the intersection of two circles (Venn diagram):
- Left circle = Movies
- Right circle = Reviews
- Result = only the overlapping middle
Key Takeaways
- Use INNER JOIN to retrieve related data from multiple tables in one query.
- It only returns matching rows.
- Always use the
ONclause to define relationships. - Specify columns for cleaner results.
- Multiple joins can be chained for more complex relationships.
Quick Example Summary
-- Basic join
SELECT Movies.title, Reviews.review
FROM Movies
INNER JOIN Reviews
ON Movies.id = Reviews.movie_id;
-- Multi-table join
SELECT Movies.title, Genres.name
FROM Movies
INNER JOIN Movies_Genres
ON Movies.id = Movies_Genres.movie_id
INNER JOIN Genres
ON Movies_Genres.genre_id = Genres.id;
SQL Aliases (Columns & Tables)
Column Aliases
- Column aliases allow you to rename output column headers in your query results.
- Useful for making results more readable and user-friendly.
Syntax
SELECT column_name AS alias_name
FROM table_name;
- The keyword
ASis optional:
SELECT column_name alias_name
FROM table_name;
Examples
SELECT Movies.title AS films, Reviews.review AS reviews
FROM Movies
INNER JOIN Reviews ON Movies.id = Reviews.movie_id;
- Without
AS:
SELECT Movies.title films, Reviews.review reviews
FROM Movies
INNER JOIN Reviews ON Movies.id = Reviews.movie_id;
Using Multiple Words in Aliases
- Use quotation marks when the alias contains spaces:
SELECT Movies.title AS "Weekly Movies", Reviews.review AS "Weekly Reviews"
FROM Movies
INNER JOIN Reviews ON Movies.id = Reviews.movie_id;
Table Aliases
- Table aliases shorten table names in queries.
- Helpful when:
- Working with long table names
- Writing complex joins
- Improving readability
Syntax
FROM table_name alias
Example
SELECT m.title
FROM Movies m;
- Here,
mis used instead ofMovies.
Using Table Aliases in Joins
- Once defined, aliases can be used throughout the query (SELECT, JOIN, WHERE, ORDER BY).
Example
SELECT m.title, r.review
FROM Movies m
INNER JOIN Reviews r ON m.id = r.movie_id;
Example
SELECT m.title, g.name
FROM Movies m
INNER JOIN Movies_Genres mg ON m.id = mg.movie_id
INNER JOIN Genres g ON mg.genre_id = g.id;
SQL Outer Joins (LEFT & RIGHT)
Overview
Outer joins allow you to combine rows from two tables even when there is no match in one of them. They help ensure that you don’t lose data from one side of the relationship.
LEFT OUTER JOIN
Purpose
- Returns all records from the left table (
Movies) - Returns matching records from the right table (
Reviews) - If no match exists, the right-side columns are filled with
NULL
Syntax
SELECT *
FROM Movies
LEFT OUTER JOIN Reviews
ON Movies.id = Reviews.movie_id;
Key Observations
- Every movie appears in the result
- Movies with multiple reviews appear multiple times
- Movies with no reviews still appear, with
NULLvalues for review columns
Example Output Insight
Don Juanappears 3 times (3 reviews)Peter Panappears once with no review (NULL values)
Refining the LEFT JOIN
Improvements
- Use table aliases
- Select only relevant columns
- Order results
Example Query
SELECT m.title, r.body
FROM Movies m
LEFT OUTER JOIN Reviews r
ON m.id = r.movie_id
ORDER BY r.id;
Result Behaviour
- Movies without reviews (e.g.
Peter Pan) appear last due to ordering byreview id
RIGHT OUTER JOIN
Purpose
- Returns all records from the right table (
Reviews) - Returns matching records from the left table (
Movies) - If no match exists, the left-side columns are filled with
NULL
Syntax
SELECT *
FROM Movies
RIGHT OUTER JOIN Reviews
ON Movies.id = Reviews.movie_id;
Scenario Highlight
- Some
movie_idvalues inReviewsare set toNULL - These reviews do not link to any movie
Key Observations
- All reviews are included
- Reviews without a corresponding movie show
NULLin movie fields
Refining the RIGHT JOIN
Example Query
SELECT m.title, r.body
FROM Movies m
RIGHT OUTER JOIN Reviews r
ON m.id = r.movie_id
ORDER BY r.id;
Result Behaviour
- All reviews listed
- Reviews with no associated movie have
NULLtitles
LEFT vs RIGHT JOIN Summary
| Join Type | Includes All From | Missing Matches Show As |
|---|---|---|
| LEFT OUTER JOIN | Left table | NULLs in right columns |
| RIGHT OUTER JOIN | Right table | NULLs in left columns |
Key Takeaways
-
Use LEFT JOIN when you care about all records from the first (left) table
-
Use RIGHT JOIN when you care about all records from the second (right) table
-
NULLvalues indicate missing relationships -
Ordering can affect where unmatched rows appear in results
-
Outer joins ensure you don’t lose unmatched data
-
LEFT JOIN = “Show everything from the left”
-
RIGHT JOIN = “Show everything from the right”
-
Useful for identifying missing relationships and incomplete data