parent
3b2fa0894e
commit
7cf133ca87
2 changed files with 322 additions and 0 deletions
@ -0,0 +1,89 @@ |
||||
--- |
||||
title: Foreign Key Constraint |
||||
description: Learn about foreign keys and how to use them effectively. |
||||
order: 170 |
||||
type: lesson-challenge |
||||
--- |
||||
|
||||
## Foreign Keys |
||||
|
||||
A foreign key is a column (or columns) that references the primary key of another table. It creates a relationship between tables and helps maintain referential integrity. |
||||
|
||||
Let's look at an example: |
||||
|
||||
```sql |
||||
CREATE TABLE books ( |
||||
id INTEGER PRIMARY KEY, |
||||
title TEXT NOT NULL, |
||||
author_id INTEGER, |
||||
|
||||
-- Creating a foreign key |
||||
FOREIGN KEY (author_id) REFERENCES authors(id) |
||||
); |
||||
``` |
||||
|
||||
In this example: |
||||
|
||||
- The `author_id` in the `books` table is a foreign key |
||||
- It references the `id` column in the `authors` table |
||||
- This creates a relationship between books and their authors |
||||
|
||||
### Why are Foreign Keys Important? |
||||
|
||||
Foreign keys help maintain data integrity by: |
||||
|
||||
1. Ensuring referenced data exists |
||||
2. Preventing orphaned records |
||||
3. Maintaining relationships between tables |
||||
|
||||
Here's a practical example: |
||||
|
||||
```sql |
||||
-- Create the authors table first |
||||
CREATE TABLE authors ( |
||||
id INTEGER PRIMARY KEY, |
||||
name TEXT NOT NULL, |
||||
email VARCHAR(100) UNIQUE |
||||
); |
||||
|
||||
-- Create the books table with a foreign key |
||||
CREATE TABLE books ( |
||||
id INTEGER PRIMARY KEY, |
||||
title TEXT NOT NULL, |
||||
author_id INTEGER, |
||||
price DECIMAL(10, 2), |
||||
|
||||
FOREIGN KEY (author_id) REFERENCES authors(id) |
||||
ON DELETE SET NULL -- Optional: what to do when referenced author is deleted |
||||
ON UPDATE CASCADE -- Optional: what to do when referenced author id is updated |
||||
); |
||||
|
||||
-- Now we can't add a book with an non-existent author_id |
||||
INSERT INTO books (title, author_id, price) |
||||
VALUES ('Invalid Book', 999, 29.99); -- This will fail if author 999 doesn't exist |
||||
``` |
||||
|
||||
### Foreign Key Actions |
||||
|
||||
When you create a foreign key, you can specify what should happen when the referenced record is deleted or updated: |
||||
|
||||
| Action | Description | |
||||
| ----------- | --------------------------------------------------------------------- | |
||||
| `CASCADE` | Delete/update the child records when parent record is deleted/updated | |
||||
| `SET NULL` | Set the foreign key to NULL when parent record is deleted/updated | |
||||
| `RESTRICT` | Prevent deletion/update of parent record if child records exist | |
||||
| `NO ACTION` | Similar to RESTRICT (default behavior in most databases) | |
||||
|
||||
For example: |
||||
|
||||
```sql |
||||
CREATE TABLE orders ( |
||||
id INTEGER PRIMARY KEY, |
||||
user_id INTEGER, |
||||
total DECIMAL(10, 2), |
||||
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) |
||||
ON DELETE CASCADE -- Delete orders when user is deleted |
||||
ON UPDATE CASCADE -- Update user_id in orders when user's id changes |
||||
); |
||||
``` |
@ -0,0 +1,233 @@ |
||||
--- |
||||
title: Primary Key Constraint |
||||
description: Learn about primary keys and how to use them effectively. |
||||
order: 160 |
||||
type: lesson-challenge |
||||
--- |
||||
|
||||
In our previous lessons, we learned about various constraints that help maintain data integrity. In this lesson, we'll look at two of the most important constraints in SQL: Primary Keys and Foreign Keys. |
||||
|
||||
## Primary Keys |
||||
|
||||
A primary key is a column (or a combination of columns) that uniquely identifies each row in a table. Think of it as a unique ID that helps us reference specific rows in our table. |
||||
|
||||
Here's an example of a table with a primary key: |
||||
|
||||
```sql |
||||
-- Creating a table with a primary key |
||||
CREATE TABLE books ( |
||||
id INTEGER PRIMARY KEY, |
||||
title VARCHAR(255) NOT NULL, |
||||
isbn VARCHAR(13), |
||||
price DECIMAL(10, 2) |
||||
); |
||||
``` |
||||
|
||||
Alternatively, there are two other syntaxes for creating primary keys: |
||||
|
||||
```sql |
||||
-- Define primary key in the constratins section |
||||
CREATE TABLE books ( |
||||
id INTEGER, |
||||
title VARCHAR(255) NOT NULL, |
||||
isbn VARCHAR(13), |
||||
price DECIMAL(10, 2), |
||||
|
||||
PRIMARY KEY (id) |
||||
); |
||||
|
||||
-- You can also name the constraint so that database |
||||
-- shows it in the error messages |
||||
CREATE TABLE books ( |
||||
id INTEGER, |
||||
title VARCHAR(255) NOT NULL, |
||||
isbn VARCHAR(13), |
||||
price DECIMAL(10, 2), |
||||
|
||||
CONSTRAINT books_identifier PRIMARY KEY (id) |
||||
-- -------^-------- |
||||
-- Name of the constraint |
||||
); |
||||
``` |
||||
|
||||
In this example, the `id` column is our primary key. Each book in the table must have a unique `id` value. For example, if we try to insert a book without and `id`, it will fail: |
||||
|
||||
```sql |
||||
-- Error: Null value in column 'id' violates not-null constraint |
||||
-- Primary key columns cannot be null |
||||
INSERT INTO books (title, isbn, price) |
||||
VALUES ('Book 1', '1234567890123', 19.99); |
||||
``` |
||||
|
||||
Similarly, if we try to insert a book with an existing `id`, it will fail: |
||||
|
||||
```sql |
||||
-- Error: duplicate key value violates unique constraint "books_pkey" |
||||
INSERT INTO books (id, title, isbn, price) |
||||
VALUES (1, 'Book 1', 'xxxxxxxxxxxxx', 9.99), |
||||
(1, 'Book 2', 'yyyyyyyyyyyyy', 20.99); |
||||
``` |
||||
|
||||
### Why are Primary Keys Important? |
||||
|
||||
In our previous lessons, we haven't been creating primary keys as I was postponing this lesson until now. But it is highly recommended to define primary keys for each table, because: |
||||
|
||||
- They help **uniquely identify** each row in a table. |
||||
- We can prevent **duplicate rows** from being inserted. |
||||
- They can be used to create **relationships** between tables. |
||||
- Primary keys are **indexed by default**, resulting in **improved query performance**. |
||||
|
||||
We will learn about indexes in the future lessons. |
||||
|
||||
### Auto-generating Primary Keys |
||||
|
||||
Most databases provide a way to automatically generate primary key values. It is not a part of the SQL standard, but many databases have their own syntax for it e.g. |
||||
|
||||
| Database | Syntax | |
||||
| ---------- | ---------------- | |
||||
| PostgreSQL | `SERIAL` | |
||||
| MySQL | `AUTO_INCREMENT` | |
||||
| SQLite | `AUTOINCREMENT` | |
||||
| SQL Server | `IDENTITY` | |
||||
| Oracle | `SEQUENCE` | |
||||
|
||||
The example below shows how to create a table with a primary key that is auto-generated in PostgreSQL: |
||||
|
||||
```sql |
||||
CREATE TABLE authors ( |
||||
id SERIAL PRIMARY KEY, |
||||
name VARCHAR(255) NOT NULL, |
||||
email VARCHAR(100) UNIQUE |
||||
); |
||||
|
||||
-- Now we can insert without specifying id |
||||
INSERT INTO authors (name, email) |
||||
VALUES ('J.K. Rowling', 'jk@example.com'), |
||||
('Stephen King', 'stephen@example.com'), |
||||
('Agatha Christie', 'agatha@example.com'); |
||||
``` |
||||
|
||||
Now if we fetch all the rows from the `authors` table: |
||||
|
||||
```sql |
||||
SELECT * FROM authors; |
||||
``` |
||||
|
||||
We will see the auto-generated `id` values for each row: |
||||
|
||||
| id | name | email | |
||||
| --- | --------------- | ------------------- | |
||||
| 1 | J.K. Rowling | jk@example.com | |
||||
| 2 | Stephen King | stephen@example.com | |
||||
| 3 | Agatha Christie | agatha@example.com | |
||||
|
||||
The database will automatically assign and increment the `id` value for each new row. |
||||
|
||||
### Composite Primary Keys |
||||
|
||||
Sometimes, you might need multiple columns to uniquely identify a row. This is called a composite primary key: |
||||
|
||||
```sql |
||||
CREATE TABLE book_editions ( |
||||
book_id INTEGER, |
||||
edition_number INTEGER, |
||||
publication_year INTEGER, |
||||
|
||||
-- Creating a composite primary key |
||||
PRIMARY KEY (book_id, edition_number) |
||||
); |
||||
``` |
||||
|
||||
In this case, a specific edition of a book is uniquely identified by both its `book_id` and `edition_number`. We can't insert a row with the same `book_id` and `edition_number` twice. |
||||
|
||||
For example, if we try to insert a row with the same `book_id` and `edition_number`: |
||||
|
||||
```sql |
||||
-- Error: duplicate key value violates unique constraint "book_editions_pkey" |
||||
INSERT INTO book_editions (book_id, edition_number, publication_year) |
||||
VALUES (1, 1, 2020), |
||||
(1, 1, 2021); |
||||
``` |
||||
|
||||
If we try to insert a row with a different `book_id`: |
||||
|
||||
```sql |
||||
-- This will work because the combination of book_id and edition_number is unique |
||||
INSERT INTO book_editions (book_id, edition_number, publication_year) |
||||
VALUES (1, 1, 2020), |
||||
(2, 1, 2021); |
||||
``` |
||||
|
||||
While we are on the topic of primary keys and uniqueness, let's also look at the `UNIQUE` constraint which can be used to enforce uniqueness on any column or a combination of columns. |
||||
|
||||
## UNIQUE Constraint |
||||
|
||||
While primary keys enforce uniqueness, sometimes you need other columns to be unique as well. The `UNIQUE` constraint ensures no duplicate values can exist in a column: |
||||
|
||||
```sql |
||||
CREATE TABLE books ( |
||||
id INTEGER PRIMARY KEY, |
||||
title VARCHAR(255) NOT NULL, |
||||
isbn VARCHAR(13) UNIQUE, -- This column must be unique |
||||
price DECIMAL(10, 2), |
||||
); |
||||
``` |
||||
|
||||
Again, just like any other constraint, here is the alternative syntax: |
||||
|
||||
```sql |
||||
-- Define in constraints section |
||||
CREATE TABLE books ( |
||||
id INTEGER PRIMARY KEY, |
||||
title VARCHAR(255) NOT NULL, |
||||
isbn VARCHAR(13), |
||||
price DECIMAL(10, 2), |
||||
|
||||
CONSTRAINT books_isbn_unique UNIQUE (isbn) |
||||
); |
||||
|
||||
-- Or without naming the constraint |
||||
CREATE TABLE books ( |
||||
id INTEGER PRIMARY KEY, |
||||
title VARCHAR(255) NOT NULL, |
||||
isbn VARCHAR(13), |
||||
price DECIMAL(10, 2), |
||||
|
||||
UNIQUE (isbn) |
||||
); |
||||
``` |
||||
|
||||
In this example, `isbn` must be unique across all rows. For example, if we try to insert a row with the same `isbn`: |
||||
|
||||
```sql |
||||
-- Error: duplicate key value violates unique constraint "books_isbn_unique" |
||||
INSERT INTO books (id, title, isbn, price) |
||||
VALUES (1, 'Book 1', '1234567890123', 19.99), |
||||
(2, 'Book 2', '1234567890123', 20.99); |
||||
``` |
||||
|
||||
> The difference between `UNIQUE` and `PRIMARY KEY` is that a table can have multiple `UNIQUE` columns but only one primary key, `UNIQUE` columns can also contain `NULL` values (unless specified otherwise), while primary keys cannot contain `NULL` values. |
||||
|
||||
### NULL Considered UNIQUE |
||||
|
||||
By default, `UNIQUE` constraint allows `NULL` values. You can change that behavior by adding `NULLS NOT DISTINCT` to the constraint i.e. |
||||
|
||||
```sql |
||||
CREATE TABLE books ( |
||||
id INTEGER PRIMARY KEY, |
||||
title VARCHAR(255) NOT NULL, |
||||
isbn VARCHAR(13) UNIQUE NULLS NOT DISTINCT, |
||||
-- ---------^-------- |
||||
price DECIMAL(10, 2), |
||||
); |
||||
``` |
||||
|
||||
In this case, `NULL` values are not considered unique and you will get an error if you try to have multiple rows with `NULL` values in the `isbn` column e.g. |
||||
|
||||
```sql |
||||
-- Error: We are trying to insert two rows with NULL values in the isbn column |
||||
INSERT INTO books (id, title, isbn, price) |
||||
VALUES (1, 'Book 1', "XYZ", 19.99), |
||||
(2, 'Book 2', NULL, 20.99), |
||||
(3, 'Book 3', NULL, 21.99); |
||||
``` |
Loading…
Reference in new issue