From 3b2fa0894eea875001f279dc9f3ab5d22b17b9c3 Mon Sep 17 00:00:00 2001 From: Kamran Ahmed Date: Fri, 27 Dec 2024 12:41:51 +0000 Subject: [PATCH] Add constraints --- .../lessons/check-constraints.md | 282 ++++++++++++++++++ .../lessons/creating-tables.md | 2 +- .../lessons/temporal-data-types.md | 1 - .../introduction/lessons/next-steps.md | 35 +++ 4 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 src/data/courses/sql/chapters/data-definition-language/lessons/check-constraints.md diff --git a/src/data/courses/sql/chapters/data-definition-language/lessons/check-constraints.md b/src/data/courses/sql/chapters/data-definition-language/lessons/check-constraints.md new file mode 100644 index 000000000..2565ac70c --- /dev/null +++ b/src/data/courses/sql/chapters/data-definition-language/lessons/check-constraints.md @@ -0,0 +1,282 @@ +--- +title: CHECK Constraints +description: Learn about check constraints in SQL and how to use them effectively. +order: 150 +type: lesson-challenge +--- + +A `CHECK` constraint is a rule that specifies what values are allowed in a column when a row is inserted or updated. Here's the basic syntax for adding a `CHECK` constraint: + +```sql +CREATE TABLE table_name ( + column_name data_type CHECK (condition) +); +``` + +Here, `condition` is the expression similar to the ones we've used in `WHERE` clauses. Database engine will evaluate this expression for each row that is inserted or updated. If the condition evaluates to `FALSE`, the database engine will reject the operation. + +Let's look at some examples to understand this better. + +### Example 1: Single Condition + +Let's create a table that stores book information with a `CHECK` constraint to ensure prices are positive: + +```sql +CREATE TABLE books ( + id INTEGER, + title TEXT, + price DECIMAL CHECK (price > 0) +); +``` + +Now if we try to insert an invalid price: + +```sql +-- This will fail because price is negative +INSERT INTO books (title, price) +VALUES ('The Great Gatsby', -15.99); + +-- This will work because price is positive +INSERT INTO books (title, price) +VALUES ('The Great Gatsby', 15.99); +``` + +Go ahead and try it out in your database. + +> ### Coding Environment Note +> +> Remember, the database resets to its initial state after your snippet is executed. So make sure to provide the entire snippet (CREATE, INSERT, SELECT) on every run. + +### Example 2: Multiple Conditions + +You can combine multiple conditions using AND and OR operators: + +```sql +CREATE TABLE inventory ( + id INTEGER, + book_id INTEGER, + quantity INTEGER CHECK (quantity >= 0 AND quantity <= 1000), + shelf_number TEXT CHECK (shelf_number LIKE 'S%') +); + +-- This will work because both quantity and +-- shelf_number have valid data +INSERT INTO inventory (id, book_id, quantity, shelf_number) +VALUES (1, 2, 23, 'S34'); +``` + +If we try adding a row with a negative quantity, the database will reject the operation and return an error. + +```sql +-- Error: CHECK constraint failed: quantity >= 0 AND quantity <= 1000 +INSERT INTO inventory (id, book_id, quantity, shelf_number) +VALUES (13, 2, -23, 'S34'); +``` + +If we try adding a row with a shelf number that doesn't start with `S`, the database will reject the operation and return an error. + +```sql +-- Error: CHECK constraint failed: shelf_number LIKE 'S%' +INSERT INTO inventory (id, book_id, quantity, shelf_number) +VALUES (13, 2, 23, 'A34'); +``` + +### Example 3: Named Constraints + +You can also give your CHECK constraints names, which makes them show up in the error messages as well as easier to reference later: + +```sql +CREATE TABLE book_reviews ( + id INTEGER, + book_id INTEGER, + rating INTEGER, + review_status TEXT, + + -- Named CHECK constraints + -- [CONSTRAINT name] CHECK (condition) + CONSTRAINT valid_rating CHECK (rating >= 1 AND rating <= 5), + CONSTRAINT valid_status CHECK ( + review_status IN ('pending', 'approved', 'rejected') + ) +); +``` + +Now if we try to insert an invalid rating, the database will reject the operation and return an error. + +```sql +-- Error: CHECK constraint failed: valid_rating +INSERT INTO book_reviews (id, book_id, rating, review_status) +VALUES (1, 2, 6, 'pending'); +``` + +If we try to insert an invalid review status, the database will reject the operation and return an error. + +```sql +-- Error: CHECK constraint failed: valid_status +INSERT INTO book_reviews (id, book_id, rating, review_status) +VALUES (1, 2, 3, 'invalid_status'); +``` + +### Example 4: Table-Level CHECK Constraints + +Sometimes you need to check conditions that involve multiple columns. In such cases, you can define a table-level CHECK constraint: + +```sql +CREATE TABLE book_sales ( + id INTEGER, + book_id INTEGER, + sale_price DECIMAL, + retail_price DECIMAL, + + -- Table-level CHECK constraint + CHECK (sale_price <= retail_price) +); +``` + +Now if we try to insert a row with a sale price that is greater than the retail price, the database will reject the operation with an error. + +```sql +-- Error: CHECK constraint failed: sale_price <= retail_price +INSERT INTO book_sales (id, book_id, sale_price, retail_price) +VALUES (1, 2, 15.99, 10.99); +``` + +If we try to insert a row with a sale price that is less than or equal to the retail price, the database will accept the operation. + +```sql +-- OK +INSERT INTO book_sales (id, book_id, sale_price, retail_price) +VALUES (1, 2, 5.99, 10.99); +``` + +--- + +## NOT NULL Constraints + +While we are discussing constraints, let's also look at another useful constraint: `NOT NULL`. The `NOT NULL` constraint ensures that a column cannot contain `NULL` values. + +For example, in the table below, we have a `name` and `price` column. We want to ensure that both columns cannot contain `NULL` values. + +```sql +CREATE TABLE products ( + id INTEGER, + name TEXT NOT NULL, + price DECIMAL NOT NULL +); +``` + +Now if we try to insert a row with a `NULL` value in either the `name` or `price` column, the database will reject the operation with an error. + +```sql +-- Error: NOT NULL constraint failed: name +INSERT INTO products (id, name, price) +VALUES (1, NULL, 10.99); + +-- Error: NOT NULL constraint failed: price +INSERT INTO products (id, name, price) +VALUES (1, 'Product 1', NULL); +``` + +--- + +## CHECK and NULL Values + +By default, CHECK constraints allow `NULL` values unless you explicitly prevent them using `NOT NULL`. + +For example in the table below you might expect the `published_year` column to be a positive number. + +```sql +CREATE TABLE books ( + id INTEGER, + published_year INTEGER CHECK (published_year > 0) +); +``` + +However, if we try to insert a row with a `NULL` value in the `published_year` column, the database will accept the operation. + +```sql +-- OK +INSERT INTO books (id, published_year) +VALUES (1, NULL); +``` + +That's because the `CHECK` constraint allows `NULL` values by default. If you want to prevent `NULL` values, you need to use the `NOT NULL` constraint as well. + +```sql +CREATE TABLE books ( + id INTEGER, + published_year INTEGER NOT NULL CHECK (published_year > 0) + -- ---^---- -------------^------------ + -- NOT NULL CHECK constraint +); +``` + +If we try to insert a row with a `NULL` value in the `published_year` column, the database will reject the operation with an error. + +```sql +-- Error: NOT NULL constraint failed: published_year +INSERT INTO books (id, published_year) +VALUES (1, NULL); +``` + +--- + +## DEFAULT Constraint + +The `DEFAULT` constraint is used to specify a default value for a column. + +For example, in the table below, we have a `published_year` column. We want to specify a default value of `2024` for the `published_year` column. We can do this using the `DEFAULT` constraint. + +```sql +CREATE TABLE books ( + id INTEGER, + published_year INTEGER DEFAULT 2024 + -- -----^------ + -- DEFAULT value +); +``` + +If we try to insert a row without a value for the `published_year` column, the database will use the default value of `2024`. + +```sql +-- OK +INSERT INTO books (id) +VALUES (1); +``` + +### DEFAULT and NULL Values + +When using `NOT NULL` and `DEFAULT` together, the `DEFAULT` value is used only if you omit a value for the column. However, if you explicitly provide a `NULL` value for the column, the database will reject the operation with an error due to the `NOT NULL` constraint. + +Let's look at an example to understand this better. + +```sql +CREATE TABLE books ( + id INTEGER, + published_year INTEGER NOT NULL DEFAULT 2024 +); +``` + +If we don't specify a value for the `published_year` column, the database will use the default value of `2024` and there will be no error. + +```sql +-- OK +INSERT INTO books (id) +VALUES (1); +``` + +However, if we explicitly provide a `NULL` value for the `published_year` column, the database will reject the operation with an error due to the `NOT NULL` constraint. + +```sql +-- Error: NOT NULL constraint failed: published_year +INSERT INTO books (id, published_year) +VALUES (1, NULL); +``` + +--- + +`CHECK` constraints are a powerful way to ensure data integrity in your database. They act as a first line of defense against invalid data and help maintain consistency in your application. + +In the next lesson, we'll look at other types of constraints that help maintain data integrity. + + diff --git a/src/data/courses/sql/chapters/data-definition-language/lessons/creating-tables.md b/src/data/courses/sql/chapters/data-definition-language/lessons/creating-tables.md index 227d0599a..83c3a52af 100644 --- a/src/data/courses/sql/chapters/data-definition-language/lessons/creating-tables.md +++ b/src/data/courses/sql/chapters/data-definition-language/lessons/creating-tables.md @@ -110,4 +110,4 @@ Create a table called `books` with the following columns: | `price` | Decimal numbers e.g. 10.99, 12.99, etc. | | `year` | Non-decimal numbers e.g. 1925, 1949, etc. | -You are required to identify the correct data types for the columns based on the description above. +You are required to identify the correct data types for the columns based on the description above. \ No newline at end of file diff --git a/src/data/courses/sql/chapters/data-definition-language/lessons/temporal-data-types.md b/src/data/courses/sql/chapters/data-definition-language/lessons/temporal-data-types.md index 0a6482bda..7f4cd178e 100644 --- a/src/data/courses/sql/chapters/data-definition-language/lessons/temporal-data-types.md +++ b/src/data/courses/sql/chapters/data-definition-language/lessons/temporal-data-types.md @@ -19,7 +19,6 @@ Given below is the list of temporal data types in SQL with their sample usage: | `TIME` | Stores only the time of day | Store hours, appointment times | | `DATETIME` | Stores both date and time | Event times, log entries | | `TIMESTAMP` | Similar to `DATETIME` but with timezone awareness | e.g. Calendar events | -| `INTERVAL` | Stores periods of time | Duration calculations, scheduling | Let's explore each of these types in detail in the following sections. diff --git a/src/data/courses/sql/chapters/introduction/lessons/next-steps.md b/src/data/courses/sql/chapters/introduction/lessons/next-steps.md index 32965fcfc..0232c4ace 100644 --- a/src/data/courses/sql/chapters/introduction/lessons/next-steps.md +++ b/src/data/courses/sql/chapters/introduction/lessons/next-steps.md @@ -7,6 +7,8 @@ type: lesson Now that we have got the theoretical part out of the way, let's dive into the practical part of SQL. In our next chapter, we will learn about the basics of SQL; we will cover the basics of selecting data from a database. This will give you a taste of what SQL is and how it works preparing you for the next chapters covering more complex topics. +--- + ## Coding Environment We don't expect you to have a database setup on your local machine. All our lessons will have the coding environment setup with the database ready for you to use and practice. We will be using a hypothetical pre-populated databases throughout this course to help you learn SQL. Additional things to note about the coding environment: @@ -14,4 +16,37 @@ We don't expect you to have a database setup on your local machine. All our less - Our database environment is not persistent. This means that if you close the browser or refresh the page, the database will be reset to its original state. - We are using SQLite for our coding environment. The concepts we will be covering, however, are the same for any other database and you are not required to know anything about SQLite to follow this course. +### Important Note on Running Snippets + +Before you continue, please keep in mind that every time you click the "Run" button, the **database resets to its initial state after the snippet is executed**. This means: + +- All previous commands and their effects are cleared +- You start with a fresh, empty database +- Only the commands in your current snippet will be executed + +For example, this sequence will not work: + +```sql +-- First Run +CREATE TABLE users (id INT, name TEXT); +-- Second Run +INSERT INTO users VALUES (1, 'Alice'); +-- Third Run +SELECT * FROM users; +``` + +The `INSERT` query will fail because the table `users` will be dropped after the first run. + +Instead, combine all related commands into a single snippet: + +```sql +-- All commands in one run: +CREATE TABLE users (id INT, name TEXT); +INSERT INTO users VALUES (1, 'Alice'); +SELECT * FROM users; +``` + +--- + + See you in the next chapter!