├── 00-setup-and-introduction-to-sql-fundamentals ├── lesson.md └── transcript.md ├── 01-create-a-table-with-sql-create ├── exercises.md ├── lesson.md └── transcript.md ├── 02-add-data-to-a-table-with-sql-insert ├── exercises.md ├── lesson.md └── transcript.md ├── 03-query-data-with-the-select-command-in-sql ├── exercises.md ├── lesson.md └── transcript.md ├── 04-update-data-in-a-table-with-sql-update ├── exercises.md ├── lesson.md └── transcript.md ├── 05-removing-data-with-sql-delete-truncate-and-drop ├── exercises.md ├── lesson.md └── transcript.md ├── 06-keep-data-integrity-with-constraints ├── exercises.md ├── lesson.md └── transcript.md ├── 07-organize-table-data-with-indexes ├── exercises.md ├── lesson.md └── transcript.md ├── 08-select-grouped-and-aggregated-data-with-sql ├── exercises.md ├── lesson.md └── transcript.md ├── 09-conditionally-select-out-filtered-data-with-sql-where ├── exercises.md ├── lesson.md └── transcript.md ├── 10-combining-tables-together-with-sql-join-statements ├── exercises.md ├── lesson.md └── transcript.md ├── 11-subquery-dynamic-datasets-in-sql ├── exercises.md ├── lesson.md └── transcript.md ├── CHANGELOG.md ├── README.md └── solutions ├── 01-create-a-table-with-sql-create-solutions.md ├── 02-add-data-to-a-table-with-sql-insert-solutions.md ├── 03-query-data-with-the-select-command-in-sql-solutions.md ├── 04-update-data-in-a-table-with-sql-update-solutions.md ├── 05-removing-data-with-sql-delete-truncate-and-drop-solutions.md ├── 06-keep-data-integrity-with-constraints-solutions.md ├── 07-organize-table-data-with-indexes-solutions.md ├── 08-select-grouped-and-aggregated-data-with-sql-solutions.md ├── 09-conditionally-select-out-filtered-data-with-sql-where-solutions.md ├── 10-combining-tables-together-with-sql-join-statements-solutions.md └── 11-subquery-dynamic-datasets-in-sql-solutions.md /00-setup-and-introduction-to-sql-fundamentals/lesson.md: -------------------------------------------------------------------------------- 1 | ## Setup 2 | ### For mac 3 | [install homebrew](https://brew.sh/) 4 | 5 | Ensure homebrew is up-to-date, run: 6 | 1. `brew doctor` 7 | 2. `brew update` 8 | 9 | Now that brew is up to date, run: 10 | 11 | `brew install postgres` 12 | 13 | ### For windows 14 | [Installer](https://www.postgresql.org/download/windows/) 15 | 16 | ### Run postgres 17 | After installation open terminal and run `psql postgres` 18 | 19 | If installed correctly, you should see output in your terminal similar to this: 20 | 21 | ```bash 22 | $ psql postgres 23 | psql (11.2) 24 | Type "help" for help. 25 | 26 | $ postgres=# 27 | ``` 28 | 29 | ### Lesson Errata 30 | if you see this error: 31 | ```text 32 | psql: could not connect to server: No such file or directory 33 | Is the server running locally and accepting 34 | connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"? 35 | ``` 36 | 37 | Run: 38 | `brew services start postgresql` 39 | 40 | If the error persists, it is likely that you have two versions of postgres running on your machine. Run this command to upgrade postgres via brew: `brew postgresql-upgrade-database`. 41 | -------------------------------------------------------------------------------- /00-setup-and-introduction-to-sql-fundamentals/transcript.md: -------------------------------------------------------------------------------- 1 | SQL stands for Structured Query Language. It's a language we use to communicate with relational databases. Relational database is the idea of storing data in tables that contain rows and columns. 2 | 3 | For example, if you think of Microsoft Excel, within Excel we have columns and we have rows. Tables are referred to as relations, columns are referred to as attributes, and each row is referred to as a record or tuple. 4 | 5 | Some popular relational databases you've probably heard of are Microsoft SQL Server, Oracle database, MySQL, and Postgres. These are popular choice because relational databases help developers and database admins easily categorize and store data that can be queried for exact data sets. 6 | 7 | They're usually easy to set up and new tables can be created without needing to modify existing applications. They also provide accurate data, because it's stored only once unless designed not to. 8 | 9 | SQL is flexible and dynamic, meaning tables and lots of data can be meshed together for one returning result and has great security practices if they are utilized. This course is designed for beginners and those who have heard of SQL but just have not had the chance to get their hands dirty with it. 10 | 11 | Some of the takeaways I want you to have after going through this course is the ability to at least read from, write to, delete from, create and update rows, columns, and tables. 12 | 13 | We'll be using `postgres` throughout this course as the database we'll run our SQL queries against. You'll find as you're working on the databases, like the ones I mentioned, don't exactly have the same types, built-in functions, errors, and other miscellaneous items. Everything that works within this course might not be 100 percent in other relational databases, but it will get you really close. 14 | 15 | Core commands like `update`, `select`, `delete`, and `create` are pretty universal between them, there are just a few subtle differences throughout each. After watching each lesson, be sure to check out the notes of the video. I'm posting links to various DB docs on the lesson topic so that you can dive more into them. I mentioned that this course is using `postgres` for each lesson. 16 | 17 | If you're on a Mac it can be easily installed through the package manager Homebrew. 18 | 19 | [Install Homebrew for Mac](https://brew.sh/) 20 | 21 | Once it's in there, all you need to do is go to your terminal and run `brew install postgres`. 22 | 23 | ### Terminal 24 | ```bash 25 | $ brew install postgress 26 | ``` 27 | 28 | If you're on Windows download the interactive installer from the Postgres docs. 29 | 30 | [Windows Postgres installer](https://www.postgresql.org/download/windows/) 31 | 32 | This installer is pretty straightforward and will get you up and running quickly. You'll know that everything was installed correctly when you type `psql postgres` in your terminal and you connect to your local database. 33 | 34 | ```bash 35 | $ psql postgres 36 | PSQL (9.6.4) 37 | Type "help" for help 38 | 39 | $ postgres=# 40 | ``` -------------------------------------------------------------------------------- /01-create-a-table-with-sql-create/exercises.md: -------------------------------------------------------------------------------- 1 | # Create a Table with SQL Create Exercises 2 | 3 | All databases have recognized Types that are accepted. `Boolean` and `int` are two common types accepted in many relational database's such as Postgres or MySQL 4 | 5 | Explore some of the types available to you [here](https://www.postgresql.org/docs/9.5/datatype.html). 6 | 7 | Now that we have a `Users` table defined, create a `Products` table with different data types. 8 | 9 | This table should have columns for: 10 | - `create_date` date for when the product is purchased 11 | - `product_id` (hint: a unique identifier) 12 | - `title` with a character limit of 50 13 | - `description` Text that describes what the product is 14 | - `price` money type for the purchase price 15 | 16 | 17 | 18 | Take it a step further by adding a column for the user that purchased the product. -------------------------------------------------------------------------------- /01-create-a-table-with-sql-create/lesson.md: -------------------------------------------------------------------------------- 1 | # Step 1 - Creating a Table 2 | 3 | ### Create a Users Table 4 | ```sql 5 | create table Users ( 6 | create_date date, 7 | user_handle uuid, 8 | last_name text, 9 | first_name text 10 | ); 11 | //-> CREATE TABLE 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /01-create-a-table-with-sql-create/transcript.md: -------------------------------------------------------------------------------- 1 | Let's create a table with SQL. Here, we're going to be using the `create` statement. We'll say `create table Users`, and then in open parentheses, we'll say `create_date`. There's going to be a `date`. `user_handle` is going to be a `uuid`. `last_name` will be a `text`. `first_name` will be a `text` as well. We'll close it off and then use a semicolon. Perfect. We've created our first table. 2 | 3 | ```sql 4 | $ postgres=# create table Users ( 5 | $ postgres(# create_date Date, 6 | $ postgres(# user_handle uuid, 7 | $ postgres(# last_name text, 8 | $ postgres(# first_name text ); 9 | CREATE TABLE 10 | postgres # 11 | ``` 12 | 13 | The main principle to keep in mind here is the `create` statement. This tells your database that we'll be creating something new. 14 | 15 | We'll use the `create` statement to add other components within our database. For this instance, we need to define what we're creating, which is a `table`. After we've established we're creating a table, we'll give it a name, `users`. 16 | 17 | Inside the parentheses, we'll define all of the columns within our new table and list the type of data that will live within this column. For example, the `create_date` column holds date types of data. Each time data is inserted into this table, the data will need to match each data type or an error will be thrown. 18 | 19 | `text` is referring to a string or a character type, and `uuid` is a universally unique identifier. Some other recognized types used in SQL are `boolean` and `int` for numbers. Each database such as Postgres and MySQL will have more granular and advanced types that can be used. 20 | 21 | I will link to some popular databases that use SQL below in the video notes. I recommend taking some time to go through these because they can vary greatly between databases. 22 | -------------------------------------------------------------------------------- /02-add-data-to-a-table-with-sql-insert/exercises.md: -------------------------------------------------------------------------------- 1 | # Add Data to a Table with SQL Insert Exercises 2 | 3 | In the previous exercise, you created a Products table, check the `solutions.md` file in the [01-create-a-table-with-sql-create](../01-create-a-table-with-sql-create/solutions.md) folder to create a `Products` table for this exercise 4 | 5 | In the lesson, you inserted data into the `User` table. 6 | 7 | Lets do the same for `Products`. 8 | 9 | ## 1. Add Static Data to Products table 10 | 11 | You'll need a `create_date`, `product_id`, `title`, `description`, `price`, and `technology`. 12 | 13 | Here's some data you can use: 14 | ``` 15 | 2019-04-09 16 | 17 | 407b4a99-e4fe-437b-9ce9-8ebe84e0a014 18 | 19 | sql fundamentals course 20 | 21 | This course is designed to take someone that has no experience with relational databases and teach them how to at least create, read, update, and delete. 22 | 23 | 100.00 24 | 25 | sql 26 | ``` 27 | 28 | ## 2. Add Dynamic Data Products table 29 | 30 | Some attibutes like `create_date` and `product_id` you don't want to generate yourself. 31 | 32 | Check out the [now](https://www.postgresql.org/docs/11/functions-datetime.html) and [uuid](https://www.postgresql.org/docs/11/uuid-ossp.html) function pages to see how you can have postgres generate these values for you. 33 | 34 | HINT: If you see this error: 35 | 36 | `No function matches the given name and argument types. You might need to add explicit type casts.` 37 | 38 | when using the `uuid` functuion you find, check out this [stack overflow post](https://stackoverflow.com/questions/43685799/postgres-uuid-type-error) for the solution. -------------------------------------------------------------------------------- /02-add-data-to-a-table-with-sql-insert/lesson.md: -------------------------------------------------------------------------------- 1 | # 2 - Adding Data 2 | 3 | ### Create a Users Table 4 | ```sql 5 | create table Users ( 6 | create_date date, 7 | user_handle uuid, 8 | last_name text, 9 | first_name text 10 | ); 11 | //-> CREATE TABLE 12 | ``` 13 | 14 | ### Insert Data 15 | ```sql 16 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'clark', 'tyler'); 17 | ``` 18 | 19 | With built in postgres functions: 20 | ```sql 21 | insert into Users (create_date, user_handle, last_name, first_name ) values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'johnson', 'patrick'); 22 | ``` 23 | 24 | Shorthand: 25 | ```sql 26 | insert into Users values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'jones', 'zac'); 27 | ``` 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /02-add-data-to-a-table-with-sql-insert/transcript.md: -------------------------------------------------------------------------------- 1 | As you can imagine, when a table is created, it contains no data from the start. The first step in making your database useful is by adding data. We'll do this by using the `insert` command. 2 | 3 | We'll say, `insert into Users (create_date, user_handle, last_name, first_name) values ('2018-06-06', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'clark', 'tyler');`. `Users` is the name of the table we're inserting data into. This first set of parentheses shows the columns that the data will match up with. 4 | 5 | ```sql 6 | insert into Users (create_date, user_handle, last_name, first_name) values ('2018-06-06', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'clark', 'tyler'); 7 | INSERT 0 1 8 | ``` 9 | 10 | One thing to take notice of is the order in which we define the columns. The data listed below in the second set of parentheses will insert according to the order these columns are defined in. 11 | 12 | When inserting data, there are two required components to work. First is the table the data is going into. Second is the actual data. We don't actually need to define the order of columns here. 13 | 14 | ```sql 15 | insert into Users values ('2018-06-06', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'jones', 'debbie'); 16 | INSERT 0 1 17 | ``` 18 | 19 | As we can see here, we did not provide the corresponding column names or data it needs to match up with. This will insert into the table in the order the columns within the table were created by. It is generally accepted that listing your columns out is best practice because it's more explicit. 20 | 21 | Keep in mind that our desired inserted data needs to match up with the defined column types. For example, if we insert into our table with only two values, we're going to get a type issue because `create_date` is a `type date`, and we're giving it a string of `jones`. 22 | 23 | ```sql 24 | insert into Users values ('jones', 'debbie'); 25 | ERROR invalid input syntax for type date: "jones" 26 | LINE 1: insert into Users values ('jones', 'debbie'); 27 | ``` 28 | 29 | If we were to fix this problem, changing `jones` to a `date`, we'd still get an error because now `debbie`, the string, does not match up with a `uuid` type. 30 | 31 | ```sql 32 | insert into Users values ('2018-06-06', 'debbie'); 33 | ERROR invalid input syntax for uuid: "debbie" 34 | LINE 1: insert into Users values ('2018-06-06', 'debbie'); 35 | ``` 36 | 37 | We also don't need to provide predefined values. Most SQL databases have built-in functions that can generate values for us. Here, we're inserting a new row into users with just the created column. We're using a built-in function in Postgres called `now`. 38 | 39 | ```sql 40 | insert into Users (create_date) values (now()); 41 | INSERT 0 1 42 | ``` 43 | 44 | The `now` function returns a date type of today's date. Finally, we have the ability to insert more than one row of data at a time. All we need to do is comma separate new sets of data. Here, we're inserting three new rows of data into our users table. 45 | 46 | ```sql 47 | insert into Users (create_date) values (now()), (now()), (now()); 48 | INSERT 0 3 49 | ``` 50 | 51 | Because we're only specifying `create_date` and passing the now to each set of data, it will provide null values for `user_handle`, `first_name`, and `last_name`. 52 | 53 | Of course, if we wanted to add more data to each row, we'd just need to define the columns here in `(create_data)`, and then provide the data here in `(now())`. 54 | 55 | You might be wondering if there's a way to bulk insert data into a table -- for example, from a csv. The answer is yes. However, it's a little too advanced for this course. I recommend looking into that if you're curious. For Postgres, it involves the copy command. 56 | -------------------------------------------------------------------------------- /03-query-data-with-the-select-command-in-sql/exercises.md: -------------------------------------------------------------------------------- 1 | # Query Data with the Select Command in SQL Exercise 2 | 3 | ## Set up 4 |
5 | 6 |
7 | If you created a `Products` table from a previous exercise, skip this query. 8 | 9 | ```sql 10 | create table Products ( 11 | create_date date, 12 | product_id uuid, 13 | title character(50), 14 | description text, 15 | price money, 16 | technology character(50) 17 | ); 18 | ``` 19 | Insert values into table: 20 | ```sql 21 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'React course', 'This course you will learn all about React.', '150.00', 'react'); 22 | 23 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Vue course', 'This course you will learn all about Vue.', '350.00', 'vue'); 24 | 25 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Angular course', 'This course you will learn all about Angular.', '450.00', 'angular'); 26 | 27 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'SQL course', 'This course you will learn all about SQL.', '550.00', 'sql'); 28 | ``` 29 |
30 | 31 | ## 1. 32 | 33 | Select all products from the table. 34 | 35 | ## 2. 36 | 37 | How many products are in the `Products` table? Don't count manually. 😉 38 | 39 | ## 3. 40 | 41 | Select all products and return only the course title. -------------------------------------------------------------------------------- /03-query-data-with-the-select-command-in-sql/lesson.md: -------------------------------------------------------------------------------- 1 | # Step 3 - Selecting Data 2 | 3 | ### Set up 4 | ```sql 5 | create table Users ( 6 | create_date date, 7 | user_handle uuid, 8 | last_name text, 9 | first_name text 10 | ); 11 | ``` 12 | 13 | ```sql 14 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'clark', 'tyler'); 15 | ``` 16 | 17 | ### Select all rows from Users Table 18 | ``` 19 | select * from Users; 20 | ``` 21 | | create_date | user_handle | last_name | first_name | 22 | | ------------------------ | ------------------------------------ | --------- | ---------- | 23 | | 2018-06-06T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | clark | tyler | 24 | | 2018-06-06T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | jones | debbie | 25 | 26 | --- 27 | 28 | ### Select all rows and current time from Users 29 | ``` 30 | select first_name, last_name, current_time from Users; 31 | ``` 32 | | first_name | last_name | current_time | 33 | | ---------- | --------- | ------------------ | 34 | | tyler | clark | 14:24:36.817649+00 | 35 | | debbie | jones | 14:24:36.817649+00 | 36 | 37 | --- 38 | ### Rename attributes on select 39 | ``` 40 | select first_name as FirstName, last_name as LastName, current_time as today from Users; 41 | ``` 42 | | firstname | lastname | today | 43 | | --------- | -------- | ------------------ | 44 | | tyler | clark | 14:21:58.592996+00 | 45 | | debbie | jones | 14:21:58.592996+00 | 46 | 47 | --- 48 | 49 | ### Select all rows with distinct last name 50 | ``` 51 | select distinct(last_name) from Users; 52 | ``` 53 | | last_name | 54 | | --------- | 55 | | clark | 56 | | jones | 57 | 58 | --- 59 | 60 | ### Run aggregate functions on select statement 61 | ```sql 62 | select count(distinct(last_name)) from Users; 63 | 64 | select count(last_name) from Users; 65 | ``` 66 | **First Query** 67 | | count | 68 | | ----- | 69 | | 2 | 70 | --- 71 | **Second Query** 72 | | count | 73 | | ----- | 74 | | 3 | 75 | -------------------------------------------------------------------------------- /03-query-data-with-the-select-command-in-sql/transcript.md: -------------------------------------------------------------------------------- 1 | With data inner table the quickest way to pull it all out is to write `select * from Users;`. As you can see, we have two rows of data instead of our `Users` table. 2 | 3 | ```sql 4 | select * from Users; 5 | create_date | user_handle | last_name | first _name 6 | --------------+--------------------------------------+-----------+------------- 7 | 2018-06-06 | a0eebc99-9c0b-42f8-bb6d-6bb9bd380a11 | clark | tyler 8 | 2018-06-06 | a0eebc99-9c0b-42f8-bb6d-6bb9bd380a11 | jones | debbie 9 | (2 rows ) 10 | 11 | ``` 12 | 13 | One of the most common tasks when working with SQL databases is to query the data from the tables using this `select` statement. The select statement is very powerful and has lots of clauses and functions that can be used with it. At a minimum, all that is needed is what columns we want to work with and from which table these columns exist on. The `*` states that we want all the columns within the defined table. We can also `select` out specific columns by comma separating them. 14 | 15 | ```sql 16 | select first_name, last_name from Users; 17 | first_name | last_name 18 | ------------+----------- 19 | tyler | clark 20 | debbie | jones 21 | (2 rows) 22 | 23 | ``` 24 | 25 | If we ask for a column that does not exist from our table, we're going to see an error. If we ask for a `middle_name` from our user's table we'll see that the column `middle_name` doesn't exist in our table. 26 | 27 | ```sql 28 | select first_name, last_name, middle_name from Users; 29 | ERROR: column "middle_name" does not exist 30 | LINE 1: select first_name, last_name, middle_name from Users; 31 | 32 | 33 | ``` 34 | 35 | However, SQL databases such as SQLite, MySQL, and Postgres have open functions. We can use one of these functions within the query and our database will treat it as a column and input a value within each row. Even though `current_time` is not a column within the user's table, it is a built-in function within Postgres so it's handling it for us. 36 | 37 | ```sql 38 | select first_name, last_name, current_time from Users; 39 | first_name | last_name | timetz 40 | ------------+-----------+------------------ 41 | tyler | clark | 22:41:42.936252-07 42 | debbie | jones | 22:41:42.936252-07 43 | (2 rows) 44 | 45 | ``` 46 | 47 | We can also alias our columns within the query. If we add, say, `select first_name as FirstName, last_name as LastName, current_time as time from Users;`, when we run this query we'll see that we've changed the way our column names have rendered. 48 | 49 | ```sql 50 | select first_name as FirstName, last_name as LastName, current_time as time from Users; 51 | firstname | lastname | time 52 | ------------+-----------+------------------ 53 | tyler | clark | 22:41:42.936252-07 54 | debbie | jones | 22:41:42.936252-07 55 | (2 rows) 56 | 57 | ``` 58 | 59 | This is critical to know when working with packages within languages like C#. We need column names to match properties of classes. One common function you'll probably use a lot when working with SQL is the `count()` function which simply returns the number of rows within our table. 60 | 61 | ```sql 62 | select count(*) from Users; 63 | count 64 | -------- 65 | 2 66 | (1 row) 67 | select count(first_name) from Users; 68 | count 69 | -------- 70 | 2 71 | (1 row) 72 | 73 | ``` 74 | 75 | It doesn't matter if you use the `*` or any combination of columns as long as they exist within the table it's going to give us a count of rows. Finally, we have the ability to do some filtering of data when pulling it out at the column level. Let's `insert` another set of data where the `first_name` and `last_name` matches data that already exists. For `(first_name, last_name)`, we're going to insert `('tyler', 'clark')`. 76 | 77 | ```sql 78 | insert into Users (first_name, last_name) values ('tyler', 'clark'); 79 | INSERT 0 1 80 | $ postgres # 81 | ``` 82 | 83 | If we `select * from Users;` table we'll find that we have two rows that have the matching first name and last name of Tyler Clark. 84 | 85 | ```sql 86 | select * from Users; 87 | create_date | user_handle | last_name | first _name 88 | --------------+--------------------------------------+-----------+------------- 89 | 2018-06-06 | a0eebc99-9c0b-42f8-bb6d-6bb9bd380a11 | clark | tyler 90 | 2018-06-06 | a0eebc99-9c0b-42f8-bb6d-6bb9bd380a11 | jones | debbie 91 | | | clark | tyler 92 | (3 rows ) 93 | 94 | ``` 95 | 96 | If we use the built-in `select distinct` function on the `(first_name)` column of the user's table we'll see that we only get two rows back. It's removing the duplicate, Tyler, from the table. 97 | 98 | ```sql 99 | select distinct (first_name) from Users; 100 | first_name 101 | -------- 102 | tyler 103 | debbie 104 | (2 row) 105 | 106 | ``` 107 | The same thing can be done for `(last_name)`. 108 | 109 | ```sql 110 | select distinct (last_name) from Users; 111 | first_name 112 | -------- 113 | clark 114 | jones 115 | (2 row) 116 | 117 | ``` 118 | 119 | What's great is SQL gives us the ability to combine functions together so we can get a count of all the distinct `last_names` within our user's table, which is two and compare that against all the rows within our user's table, which is three. 120 | 121 | ```sql 122 | select count (distinct(last_name)) from Users; 123 | count 124 | -------- 125 | 2 126 | (1 row) 127 | select count (last_name) from Users; 128 | count 129 | -------- 130 | 3 131 | (1 row) 132 | ``` -------------------------------------------------------------------------------- /04-update-data-in-a-table-with-sql-update/exercises.md: -------------------------------------------------------------------------------- 1 | # Update Data in a Table with SQL Update Exercises 2 | 3 | ## Set up 4 |
5 | 6 |
7 | If you created a `Products` table from a previous exercise, skip this query. 8 | 9 | ```sql 10 | create table Products ( 11 | create_date date, 12 | product_id uuid, 13 | title character(50), 14 | description text, 15 | price money, 16 | technology character(50) 17 | ); 18 | ``` 19 | Insert values into table: 20 | ```sql 21 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'React course', 'This course you will learn all about React.', '150.00', 'react'); 22 | 23 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Vue course', 'This course you will learn all about Vue.', '350.00', 'vue'); 24 | 25 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Angular course', 'This course you will learn all about Angular.', '450.00', 'angular'); 26 | 27 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'SQL course', 'This course you will learn all about SQL.', '550.00', 'sql'); 28 | ``` 29 |
30 | 31 | ## 1. 32 | 33 | Update the `price` in the row where `title` is equal to `React course` to 300.00. 34 | 35 | ## 2. 36 | 37 | Update the both the `price` and `description` of the row where `title` is equal to `SQL course`. 38 | -------------------------------------------------------------------------------- /04-update-data-in-a-table-with-sql-update/lesson.md: -------------------------------------------------------------------------------- 1 | # Step 4 - Updating Data 2 | 3 | ```sql 4 | update Users set last_name = 'berry', first_name = 'jerry' where last_name = 'clark'; 5 | ``` 6 | | create_date | user_handle | last_name | first_name | 7 | | ------------------------ | ------------------------------------ | --------- | ---------- | 8 | | 2018-06-06T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | jones | debbie | 9 | | 2018-06-06T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | berry | jerry | 10 | | 2018-06-06T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | berry | jerry | 11 | 12 | --- 13 | -------------------------------------------------------------------------------- /04-update-data-in-a-table-with-sql-update/transcript.md: -------------------------------------------------------------------------------- 1 | Our users' table currently has two rows of data, a `tyler clark` and a `debbie jones` that currently share the same user handle and `create_date`. 2 | 3 | ```sql 4 | select * from Users; 5 | create_date | user_handle | last_name | first _name 6 | --------------+--------------------------------------+-----------+------------- 7 | 2018-06-06 | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | clark | tyler 8 | 2018-06-06 | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | jones | debbie 9 | (2 rows ) 10 | 11 | ``` 12 | 13 | We want our `user_handle` to be unique, which is why when we created this table, we gave this column a `uuid` type. Let's update my `user_handle` to be a different value. Postgres has a handy `create extension` we can bring in that will automatically generate a random `uuid` for us. 14 | 15 | ```sql 16 | create extension "uuid-ossp"; 17 | CREATE EXTENSION 18 | ``` 19 | 20 | I'll post links in the description on how to work with `uuid`'s in other databases. Now with this extension created, we can update our `Users` table with a new `user_handle`. 21 | 22 | ```sql 23 | update Users set user_handle = uuid_generate_v4(); 24 | UPDATE 2 25 | 26 | ``` 27 | 28 | When working with the update command, there are three pieces of data needed. First is the name of the table and column we're updating. Here, we provide the table name and column name separated by this `set` word, `update Users set user_handle`. Second is the new value that we want to update the row with, `uuid_generate_v4();`. We'll do that by using the equal sign,`=`. Finally, which row to update? You might have noticed that we actually ended up updating both rows of data when we just wanted to update my `user_handle`. 29 | 30 | ```sql 31 | select * from Users; 32 | create_date | user_handle | last_name | first _name 33 | --------------+--------------------------------------+-----------+------------- 34 | 2018-06-06 | ddda5534-f29b-4583-83c0-21b84e0c9786 | clark | tyler 35 | 2018-06-06 | 6ab3b2d2-8e02-45e4-890c-61a67cd43f31 | jones | debbie 36 | (2 rows ) 37 | ``` 38 | 39 | While it did accomplish our goal of having unique user handles, if we're not careful, we could have shot ourselves in the foot by accidentally losing critical data. When working with SQL, commands like `select`, `update`, `delete`, these are looping commands, meaning unless a condition is passed it will loop over each row of data. Ideally, what we should have done is add a `where` clause on our command that only updated the `user_handle` for the row where the `last_name = 'clark';`. 40 | 41 | ```sql 42 | update Users set user_handle = uuid_generate_v4() where last_name = 'clark'; 43 | UPDATE 1 44 | ``` 45 | 46 | We'll get more into filtering and the `where` clause in another video. For now, all you needed to understand is that when updating, unless a condition is provided like we did the `last_name = 'clark'`, it will apply to every single row in our table. 47 | 48 | ```sql 49 | select * from Users; 50 | create_date | user_handle | last_name | first _name 51 | --------------+--------------------------------------+-----------+------------- 52 | 2018-01-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 53 | 2018-06-06 | fh37294e-f839-f783-9ffe-7fh3os789822 | clark | tyler 54 | (2 rows ) 55 | ``` 56 | 57 | Finally, we don't have to update one column at a time. We can update more than one column by simply comma separating them. 58 | 59 | ```sql 60 | update Users set user_handle = uuid_generate_v4(), first_name = 'danny' where last_name = 'clark'; 61 | UPDATE 1 62 | 63 | ``` 64 | 65 | By adding `first_name = 'danny'`, I'm updating both my `user_handle` and my `first_name`. 66 | 67 | ```sql 68 | select * from Users; 69 | create_date | user_handle | last_name | first _name 70 | --------------+--------------------------------------+-----------+------------- 71 | 2018-01-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 72 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | danny 73 | (2 rows ) 74 | ``` -------------------------------------------------------------------------------- /05-removing-data-with-sql-delete-truncate-and-drop/exercises.md: -------------------------------------------------------------------------------- 1 | # Removing Data with SQL Delete, Truncate, and Drop Exercises 2 | 3 | ## Set up 4 |
5 | 6 |
7 | If you created a `Products` table from a previous exercise, skip this query. 8 | 9 | ```sql 10 | create table Products ( 11 | create_date date, 12 | product_id uuid, 13 | title character(50), 14 | description text, 15 | price money, 16 | technology character(50) 17 | ); 18 | ``` 19 | Insert values into table: 20 | ```sql 21 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'React course', 'This course you will learn all about React.', '150.00', 'react'); 22 | 23 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Vue course', 'This course you will learn all about Vue.', '350.00', 'vue'); 24 | 25 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Angular course', 'This course you will learn all about Angular.', '450.00', 'angular'); 26 | 27 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'SQL course', 'This course you will learn all about SQL.', '550.00', 'sql'); 28 | ``` 29 |
30 | 31 | 32 | ## 1. 33 | 34 | We no longer offer the React course. Delete this (where `title` equals `React course`) row from our `Products` table. 35 | 36 | ## 2. 37 | 38 | Actually, we're getting rid of all our products. Delete every row in the `Products` table. 39 | 40 | ## 3. 41 | 42 | Lets make that perminate. Delete the `Products` table from our database. -------------------------------------------------------------------------------- /05-removing-data-with-sql-delete-truncate-and-drop/lesson.md: -------------------------------------------------------------------------------- 1 | # Step 5 - Deleting Data 2 | 3 | 4 | ### Delete a Row 5 | ```sql 6 | delete from Users where last_name = 'Jones'; 7 | ``` 8 | 9 | ### Delete all data in a table 10 | ```sql 11 | truncate table Users; 12 | ``` 13 | 14 | ### Delete the Table 15 | ```sql 16 | drop table Users; 17 | ``` -------------------------------------------------------------------------------- /05-removing-data-with-sql-delete-truncate-and-drop/transcript.md: -------------------------------------------------------------------------------- 1 | Our `Users` table currently has two rows of data, one for `danny clark` and a `debbie jones`. 2 | 3 | ```sql 4 | select * from Users; 5 | create_date | user_handle | last_name | first _name 6 | --------------+--------------------------------------+-----------+------------- 7 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | danny 8 | 2018-1-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 9 | 10 | (2 rows ) 11 | ``` 12 | 13 | When we need to actually remove rows from our tables, instead of just updating column data, we'll use the `delete` command. If we don't put a `where` clause with our statement here, it's going to loop over each row over our table and delete everything. Make sure, before running the `delete` command on your table, you have a conditional clause that targets only the rows you want to delete. 14 | 15 | ```sql 16 | delete from Users where last_name = 'clark'; 17 | DELETE 1 18 | ``` 19 | 20 | After defining which table we're removing rows from, we're saying, delete all the rows where the `last_name` column has a value of the text `clark`. 21 | 22 | ```sql 23 | select * from Users; 24 | create_date | user_handle | last_name | first _name 25 | --------------+--------------------------------------+-----------+------------- 26 | 2018-01-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 27 | (1 rows ) 28 | ``` 29 | 30 | We're also able to add other combinations of conditions here within the `where` clause. 31 | For example, we could say, `where last_name = 'clark' and first_name = 'danny';`, or even use the `or` statement instead of the `and` statement, as well. The key point here is, you want to make sure you're targeting the correct rows of data when deleting so that you don't actually lose the wrong rows. If you wanted to delete everything in our table, I mentioned you could just use the `delete` command without a condition. 32 | 33 | However, using `truncate` is a more performant way to do so. 34 | 35 | ```sql 36 | truncate Users; 37 | TRUNCATE TABLE 38 | ``` 39 | 40 | ```sql 41 | select * from Users; 42 | create_date | user_handle | last_name | first _name 43 | --------------+--------------------------------------+-----------+------------- 44 | (0 rows ) 45 | ``` 46 | 47 | Unlike the `delete` command, it doesn't scan over the entire table. We also have the ability to `truncate` more than one table with just one statement by listing the other tables with commas. 48 | 49 | Finally, if we're trying to remove the table completely from our database, we use the `drop` command. 50 | 51 | ```sql 52 | drop table Users; 53 | DROP TABLE 54 | ``` 55 | 56 | Once we run this command, all of the data is deleted and we cannot query anything from this table. 57 | 58 | ```sql 59 | select * from Users; 60 | ERROR: relation "users" does not exist 61 | LINE 1: select * from Users; 62 | ``` -------------------------------------------------------------------------------- /06-keep-data-integrity-with-constraints/exercises.md: -------------------------------------------------------------------------------- 1 | # Select Grouped and Aggregated Data with SQL Exercises 2 | 3 | ## Set up. 4 | Up to this point we haven't had any constraints added to our data. We will need re-create the `Products` table with the constraints that we need. 5 | 6 | Run `drop table Products` to get ready for this exercise. 7 | 8 | ## 1. 9 | ```sql 10 | create table Products ( 11 | create_date date, 12 | product_id uuid, 13 | title character(50), 14 | description text, 15 | price money, 16 | technology character(50) 17 | ); 18 | ``` 19 | Modify the create statement above to ensure that all attributes (except the `description`) are always present in the database as well as setting the `product_id` as the primary key. -------------------------------------------------------------------------------- /06-keep-data-integrity-with-constraints/lesson.md: -------------------------------------------------------------------------------- 1 | # Step 6 - Working with Constraints 2 | 3 | ### Create a Users table with Primary key set to user_handle 4 | ``` 5 | create table Users ( 6 | create_date date, 7 | user_handle uuid, 8 | last_name text, 9 | first_name text, 10 | constraint PK_Users primary key (user_handle) 11 | ); 12 | ``` 13 | 14 | ### Create a Users table where no values can be null (except `last_name`) and the `user_handle` as unique 15 | ```sql 16 | create table Users ( 17 | create_date date not null, 18 | user_handle uuid not null unique, 19 | last_name text, 20 | first_name text not null 21 | ); 22 | ``` 23 | 24 | ### Create a table with a foreign key 25 | ```sql 26 | create table Purchases ( 27 | date date not null, 28 | user_handle uuid references Users (user_handle), 29 | sku uuid not null, 30 | quantity int not null 31 | ); 32 | ``` -------------------------------------------------------------------------------- /06-keep-data-integrity-with-constraints/transcript.md: -------------------------------------------------------------------------------- 1 | One of relational databases best strengths is the ability to flatten data across many tables. They can be independent from each other, or we can connect them together. Adding a `constraint` to tables is how we can connect them together, and make sure our data keeps its integrity, and as we scale it does so efficiently. 2 | 3 | Now let's create a `Users` table, `create table Users (` We'll give it `create_date date`, a `user_handle uuid`, `last_name text`, `first_name text`, and then we're going to do `constraint PK_users primary key (user_handle)`. 4 | 5 | A primary key is a column or a group of columns used to identify a row uniquely in a table. 6 | 7 | ```sql 8 | create table Users ( 9 | create_date date, 10 | user_handle uuid, 11 | last_name text, 12 | first_name text, 13 | constraint PK_users primary key (user_handle) 14 | ); 15 | CREATE TABLE 16 | ``` 17 | 18 | It could be created by defining it as a `constraint` as we did here, or since we only used one column as the key, we could have written it before the closing comma of this line for `user_handle` by writing the words primary key. A table can only have one primary key, and whatever is defined in our `constraint`, the value inserted into the column or columns needs to be not `null` and unique. What we're saying here, is that this table cannot have more than one distinct user handle in it, or we'll get an error. 19 | 20 | ```sql 21 | insert into Users values ('2018-06-06', 'a0eebc99-9c0b-42f8-bb6d-6bb9bd380a11', 'clark', 'tyler'); 22 | INSERT 01 23 | insert into Users values ('2018-06-06', 'a0eebc99-9c0b-42f8-bb6d-6bb9bd380a11', 'clark', 'tyler'); 24 | ERROR: duplicate key value violates unique constraint "pk_users" 25 | DETAIL: Key (user_handle)=(a0eebc99-9c0b-42f8-bb6d-6bb9bd380a11) already exists 26 | ``` 27 | 28 | As you can see, this helps keep our data in check, because two users in our table with the same `user_handle` could cause us some real issues down the road. 29 | 30 | The `PK_users` is the name of the key we're giving it. You don't have to give it a name, Postgres and most databases will automatically create a name for you if you don't give it one. 31 | 32 | ```sql 33 | insert into Users values ('2018-06-06', null, 'clark', 'tyler'); 34 | ERROR: null value in column "user_handle" violates not-null constraint 35 | DETAIL: Failing row contains (2018-06-06, null, clark, tyler). 36 | ``` 37 | 38 | As I mentioned before, we cannot insert a `null` value in a primary key. It's recommended to always give your table a primary key whenever you create a new table. Now if you wanted to make sure your users give you an email when they're signing up, but you don't want the email as part of your primary key, you can use the `not null` constraint. While we're at it, we probably also want to make sure we always have a `create_date` and a `first_name` as well. After dropping our `Users` table, let's recreate it, but we're going to add this `not null` statement at the end of the columns we care about not being null. Let's go make `create_date`, `user_handle` and `first_name`. 39 | 40 | ```sql 41 | create table Users ( 42 | create_date date not null, 43 | user_handle uuid not null, 44 | last_name text, 45 | first_name text not null); 46 | ); 47 | CREATE TABLE 48 | ``` 49 | 50 | With these constraints in place, we can now rest easy at night knowing that our data in our tables is a little bit more secure. 51 | 52 | ```sql 53 | postgres=# insert into Users values (null, uuid_generate_v4(), 'Jones', 'Katie'); 54 | ERROR: null value in column "create_date" violates not-null constraint 55 | DETAIL: Failing row contains (null, dbdfbe7f-3508-4495-b7c8-2701cc52edca, Jones, Katie). 56 | ``` 57 | 58 | Also my own personal opinion is to avoid dealing with nulls in databases as much as possible. They can cause problems without you even knowing. 59 | 60 | ```sql 61 | postgres=# insert into Users values (now(), uuid_generate_v4(), 'Jones', null); 62 | ERROR: null value in column "first_name" violates not-null constraint 63 | DETAIL: Failing row contains (2019-03-18, 02f0d24d-c502-4c56-a4c0-559518db94ff, Jones, null). 64 | ``` 65 | 66 | Similar to the primary key `constraint`, the `unique` constraint make sure that values stored in a column or a group of columns are unique across rows in the table. 67 | 68 | ```sql 69 | create table Users ( 70 | create_date date not null, 71 | user_handle uuid not null unique, 72 | last_name text, 73 | first_name text not null); 74 | ); 75 | CREATE TABLE 76 | insert into Users values ('2019-01-10', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'johnson', 'patrick'); 77 | INSERT 01 78 | insert into Users values ('2019-01-10', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'johnson', 'patrick'); 79 | ERROR: duplicate key value violates unique constraint "users_user_handle_key" 80 | DETAIL: Key (user_handle)=(a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11) already exists. 81 | ``` 82 | 83 | As you can see, we can combine concern constraints together, giving us the flexibility to make sure we keep our data in a maintainable state. 84 | 85 | ```sql 86 | drop table Users; 87 | DROP TABLE 88 | ``` 89 | 90 | Let's wrap up by recreating our `Users` table and the desired output. `create_date date not null`, the `user_handle` is unique and `not null` as our `primary key`. Users can have a `null` for a `last_name`, and our `first_name` is `not null` as well. 91 | 92 | ```sql 93 | create table Users ( 94 | create_date date not null, 95 | user_handle uuid primary key, 96 | last_name text, 97 | first_name text not null, 98 | ); 99 | CREATE TABLE 100 | ``` 101 | 102 | We want to start tracking all the purchases our users make, so we'll create a `Purchases` table. We want our data between the two tables to be true, meaning we should never have users make purchases that are not in our `Users` table. How difficult would it be to find that people are making purchases and we don't have their data in our users table? We can do that by creating a `foreign key` between the two tables. By adding this `references` constraint here, `user_handle uuid references Users (user_handle)`, we're adding a `foreign key` that states whatever values inserted within `Purchases`, it needs to exist on the `Users` table as well. 103 | 104 | ```sql 105 | create table purchases ( 106 | date date not null, 107 | user_handle uuid references Users (user_handle), 108 | sku uuid not null, 109 | quantity int not null, 110 | ); 111 | CREATE TABLE 112 | ``` 113 | 114 | With that in place, if we try to `insert` a random `user_handle` into `Purchases`, we get an error. 115 | 116 | ```sql 117 | insert into Purchases values ('2019-02-02', 'uuid_generate_v4()', uuid_generate_v4(), 1); 118 | ERROR: insert or update on table "purchases" violates foreign key constraint "purchases_user_handle_fkey" 119 | DETAIL: Key (user_handle)=(479a7cc9-8bdf-42c6-b17f-371f55051142) is not present in table "users". 120 | ``` 121 | 122 | It tells us that we're violating our `foreign key constraint`. If you're curious, you can add constraints to already created tables through the alter table statement. 123 | -------------------------------------------------------------------------------- /07-organize-table-data-with-indexes/exercises.md: -------------------------------------------------------------------------------- 1 | ## Set up 2 |
3 | If data exists in the `Users` and `Products` tables: 4 | ```sql 5 | truncate Products; 6 | truncate Users; 7 | ``` 8 | 9 |
10 | ```sql 11 | create table Users ( 12 | create_date date, 13 | user_handle uuid, 14 | last_name text, 15 | first_name text 16 | ); 17 | ``` 18 | ```sql 19 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', '4ff119f0-91b1-4020-8005-69bf0dd8b492', 'clark', 'tyler'); 20 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', 'jones', 'debbie'); 21 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', '3bd67317-0efa-48c9-914c-42234072d94b', 'freemon', 'mary'); 22 | ``` 23 | 24 | ```sql 25 | create table Products ( 26 | create_date date, 27 | product_id uuid, 28 | title character(50), 29 | description text, 30 | price money, 31 | technology character(50) 32 | ); 33 | ``` 34 | Insert values into table: 35 | ```sql 36 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'short React course', 'This course you will start to learn about React.', '50.00', 'react'); 37 | 38 | insert into Products values (now(), '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 'React course', 'This course you will learn all about React.', '150.00', 'react'); 39 | 40 | insert into Products values (now(), '13e55094-00d5-4c9b-bd8e-ce38072ae551', 'short Vue course', 'This course you will start to learn about Vue.', '50.00', 'vue'); 41 | 42 | insert into Products values (now(), '562951b6-3648-42fd-b49e-156c6a7edf60', 'Vue course', 'This course you will learn all about Vue.', '350.00', 'vue'); 43 | 44 | insert into Products values (now(), '18c299a8-772a-424b-841e-f3d082019271', 'short Angular course', 'This course you will start learning Angular.', '50.00', 'angular'); 45 | 46 | insert into Products values (now(), '40c88e1e-0910-4017-9b6f-12337e22183a', 'Angular course', 'This course you will learn all about Angular.', '450.00', 'angular'); 47 | 48 | insert into Products values (now(), '75f9eaba-136e-4b79-9579-5fd47b48797f', 'SQL course', 'This course you will learn all about SQL.', '550.00', 'sql'); 49 | ``` 50 | 51 | ```sql 52 | create table Purchases (date date, user_handle uuid, sku uuid, quantity int); 53 | ``` 54 | 55 | ```sql 56 | insert into Purchases values ('2019-04-22', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '75f9eaba-136e-4b79-9579-5fd47b48797f', 1); 57 | insert into Purchases values ('2019-11-23', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '40c88e1e-0910-4017-9b6f-12337e22183a', 3); 58 | insert into Purchases values ('2019-07-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '13e55094-00d5-4c9b-bd8e-ce38072ae551', 1); 59 | insert into Purchases values ('2019-09-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 2); 60 | insert into Purchases values ('2019-05-23', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', '75f9eaba-136e-4b79-9579-5fd47b48797f', 6); 61 | insert into Purchases values ('2019-11-02', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', '40c88e1e-0910-4017-9b6f-12337e22183a', 4); 62 | insert into Purchases values ('2019-04-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '40c88e1e-0910-4017-9b6f-12337e22183a', 2); 63 | insert into Purchases values ('2019-11-02', '3bd67317-0efa-48c9-914c-42234072d94b', '75f9eaba-136e-4b79-9579-5fd47b48797f', 7); 64 | insert into Purchases values ('2019-02-02', '3bd67317-0efa-48c9-914c-42234072d94b', '562951b6-3648-42fd-b49e-156c6a7edf60', 1); 65 | insert into Purchases values ('2019-04-23', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 1); 66 | insert into Purchases values ('2019-04-02', '3bd67317-0efa-48c9-914c-42234072d94b', '18c299a8-772a-424b-841e-f3d082019271', 4); 67 | insert into Purchases values ('2019-11-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '562951b6-3648-42fd-b49e-156c6a7edf60', 1); 68 | insert into Purchases values ('2019-10-23', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 3); 69 | insert into Purchases values ('2019-04-12', '3bd67317-0efa-48c9-914c-42234072d94b', '13e55094-00d5-4c9b-bd8e-ce38072ae551', 1); 70 | insert into Purchases values ('2019-02-15', '3bd67317-0efa-48c9-914c-42234072d94b', '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 2); 71 | ``` 72 |
73 | 74 | 75 | ## 1. 76 | 77 | Create an index, `test1_product_id_index`, on the `Products` table taking into account all the `product_id`s. 78 | 79 | ## 2. 80 | 81 | Verify that `test1_product_id_index` was added to the `Products` table by displaying the table. 82 | 83 | ## 3. 84 | You've noticed you query on `product_id` and `technology` quite a lot. Create an index, `test1_product_id_and_technology_index`, on both of these attributes. -------------------------------------------------------------------------------- /07-organize-table-data-with-indexes/lesson.md: -------------------------------------------------------------------------------- 1 | # Step 7 - Working with Indexes 2 | 3 | ### Create an index on the Users Table 4 | ``` 5 | create index test1_user_handle_index ON Users (user_handle); 6 | ``` 7 | 8 | ### Delete an index on the Users Table 9 | ``` 10 | drop index test1_user_handle_index; 11 | ``` -------------------------------------------------------------------------------- /07-organize-table-data-with-indexes/transcript.md: -------------------------------------------------------------------------------- 1 | Imagine going to math class at school and you're given a book that put all of the topics, such as geometry and algebra, in an unorganized manner. 2 | 3 | Everything was spread out and jumping between topic and topic as you read through the book. Chapters within your math book, and any book, help organize the information and can put similar groups of topics together so that it's easy to navigate and learn. 4 | 5 | Similar to chapters in our math books, when we insert data into our tables, we can tell our tables how to organize this data. Adding what's called an index to our tables is one of the best forms of database performance you can do. An index allows the database to go to predefined chapters, if you will, that we can define for it. 6 | 7 | Our `Users` table currently has three rows of data. 8 | 9 | ```sql 10 | $ postgres=# select * from Users; 11 | create_date | user_handle | last_name | first _name 12 | --------------+--------------------------------------+-----------+------------- 13 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 14 | 2019-02-01 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 15 | 2010-01-10 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | freemon | mary 16 | (3 rows) 17 | ``` 18 | 19 | When we query from this table, let's say that we almost exclusively just care about individual `user_handles`. We can create an index from this table by saying,` create index test1_user_handle_index on Users table (user_handle);`. Perfect. 20 | 21 | ```sql 22 | $ postgres=# create index test1_user_handle_index on Users (user_handle); 23 | CREATE INDEX 24 | $ postgres=# 25 | ``` 26 | 27 | Let's look at this statement again. The `create` command does exactly as it seems. It's creating an `index`. Then this part, `test1_user_handle_index` is the name of what we're calling it. It can be whatever you want, but you might want to try to make it something meaningful for your personal work. 28 | 29 | Next, we define the table this `index` will live on and what sets of columns we want to organize our data by. We could pass through any number of columns here. We can also `create` another `index` on the same table that organizes data behind the scenes by `(user_handle, create_date)`. 30 | 31 | ```sql 32 | $ postgres=# create index test1_user_handle_and_create_date_index on Users (user_handle, create_date); 33 | CREATE INDEX 34 | $ postgres=# 35 | ``` 36 | 37 | This would be great if we constantly queried out from this table where `user_handle` equals blank and `create_date` was between certain dates. Each database has its own way of showing what indexes are on the table. In Postgres, we just type `\d` and the table name. 38 | 39 | ```sql 40 | $ postgres=# select * from Users where user_handle = '' and create_date between '' and ''; 41 | $ postgres=# \d Users; 42 | Table "public.users" 43 | Column | Type | Modifiers 44 | --------------+-------+----------- 45 | create_date | date | 46 | user_handle | uuid | 47 | last_name | text | 48 | first_name | text | 49 | Indexes: 50 | "test1_user_handle_and_create_date_index" btree (user_handle, create_date) 51 | "test1_user_handle_index" btree (user_handle) 52 | 53 | $ postgres=# 54 | ``` 55 | 56 | Here, we can see the two indexes that we've created. 57 | 58 | To remove an `index`, we simply use the `drop` command with the name of the `index` we've created. 59 | 60 | ```sql 61 | $ postgres=# drop index test1_user_handle_index; 62 | DROP INDEX 63 | $ postgres=# \d Users; 64 | Table "public.users" 65 | Column | Type | Modifiers 66 | --------------+-------+----------- 67 | create_date | date | 68 | user_handle | uuid | 69 | last_name | text | 70 | first_name | text | 71 | Indexes: 72 | "test1_user_handle_and_create_date_index" btree (user_handle, create_date) 73 | 74 | $ postgres=# 75 | ``` 76 | 77 | That's all that's needed to remove an `index`. At first glance, you might be thinking, "Why not create many indexes on a table?" Although indexes are designed to enhance the database's performance, there are times when you should avoid them. 78 | 79 | For example, don't use indexes on small tables, tables that have frequent large batch updates or insert operations, and where columns are frequently manipulated. If you think back to our math book example, imagine now a very large math book that constantly had topics added to and removed from. 80 | 81 | Without organizing them in chapters, it's quick and easy to just add the info to the end of the book. However, with chapters, with each insert, we need to scan all of the indexes and make sure we put the right data in the right location. This creates a lot of overhead and can actually cause you more problems than it helps. 82 | 83 | Now, we could spend hours talking about indexes. There are a lot of different types, such as partial, implicit, and unique indexes. However, this is a basic and the most common example of using them. If you're interested, I'll be posting links in the video's notes for more information. 84 | -------------------------------------------------------------------------------- /08-select-grouped-and-aggregated-data-with-sql/exercises.md: -------------------------------------------------------------------------------- 1 | # Select Grouped and Aggregated Data with SQL Exercises 2 | 3 | ## Set up 4 |
5 | 6 |
7 | If you created a `Products` table from a previous exercise, skip this query. 8 | 9 | ```sql 10 | create table Products ( 11 | create_date date, 12 | product_id uuid, 13 | title character(50), 14 | description text, 15 | price money, 16 | technology character(50) 17 | ); 18 | ``` 19 | Insert values into table: 20 | ```sql 21 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'short React course', 'This course you will start to learn about React.', '50.00', 'react'); 22 | 23 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'React course', 'This course you will learn all about React.', '150.00', 'react'); 24 | 25 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'short Vue course', 'This course you will start to learn about Vue.', '50.00', 'vue'); 26 | 27 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Vue course', 'This course you will learn all about Vue.', '350.00', 'vue'); 28 | 29 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'short Angular course', 'This course you will start learning Angular.', '50.00', 'angular'); 30 | 31 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Angular course', 'This course you will learn all about Angular.', '450.00', 'angular'); 32 | 33 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'SQL course', 'This course you will learn all about SQL.', '550.00', 'sql'); 34 | ``` 35 |
36 | 37 | ## 1. 38 | 39 | Count up the `price` of all the products in our `Products` table. 40 | 41 | Hint: You'll need to use a new aggregate function. Check out [the docs](https://www.postgresql.org/docs/11/functions-aggregate.html) to learn more. 42 | 43 | ## 2. 44 | Find the highest `price` for each given `technology` and display the `technology` with the `price`. -------------------------------------------------------------------------------- /08-select-grouped-and-aggregated-data-with-sql/lesson.md: -------------------------------------------------------------------------------- 1 | # Step 8 - Aggregate functions and grouping data 2 | 3 | ### Find the lowest value create_date in Table 4 | ``` 5 | select min(create_date) from Users; 6 | ``` 7 | 8 | ### Find the highest value create_date in Table 9 | ``` 10 | select max(create_date) from Users; 11 | ``` 12 | 13 | ### Count all users with the same last name 14 | ``` 15 | select count(*), last_name from Users group by last_name; 16 | ``` 17 | -------------------------------------------------------------------------------- /08-select-grouped-and-aggregated-data-with-sql/transcript.md: -------------------------------------------------------------------------------- 1 | Our `Users` table currently has four rows of data. We've got a `tyler`, `debbie`, `mary`, and `patrick`. They each have unique user handles, but two of them share the same create date, 2019 January 10th. One has one in 2019 and the other is February 1st of 2019. 2 | 3 | ```sql 4 | select * from Users; 5 | create_date | user_handle | last_name | first _name 6 | --------------+--------------------------------------+-----------+------------- 7 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 8 | 2019-02-01 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 9 | 2010-01-10 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | freemon | mary 10 | 2018-01-10 | ddda5534-f29b-45d3-83c0-21b84e0c9786 | johnson | patrick 11 | (4 rows ) 12 | 13 | ``` 14 | 15 | When weselect out data, I want to be able to group common column values together. For instance, I want to get a `count` of shared `create_dates`. 16 | 17 | ```sql 18 | select count(*) from Users group by create_date; 19 | count 20 | --------- 21 | 2 22 | 1 23 | 1 24 | 25 | (3 rows) 26 | 27 | ``` 28 | 29 | The `group by` clause does exactly what you would assume. It combines the rows returned from theselect statement into groups. This is telling us that there are three groups of rows. Even though there are four rows in our users table, since we're grouping by `create_date`, and two rows share the same value, we get three groups. Just to show both sides, when none of the rows share, let's say, a `user_handle`, we'll get those four rows. 30 | 31 | ```sql 32 | select count(*) from Users group by user_handle; 33 | count 34 | --------- 35 | 1 36 | 1 37 | 1 38 | 1 39 | 40 | (4 rows) 41 | 42 | ``` 43 | 44 | Just seeing the count isn't really helpful, because we don't know which create dates are actually shared. Let's pull that out as well inside of our `select` statement. Now we know that the January 10th date is the one that has two rows grouped together. 45 | 46 | ```sql 47 | select count(*), create_date from Users group by create_date; 48 | count | create_date 49 | ----------+----------------- 50 | 2 | 2019-01-10 51 | 1 | 2018-06-06 52 | 1 | 2019-02-01 53 | 54 | (3 rows) 55 | 56 | ``` 57 | 58 | Let's also pull out the `first_name` column values as well. As you can see, we're getting an error. 59 | 60 | ```sql 61 | select count(*), create_date, first_name from Users group by create_date; 62 | ERROR: column "users.first_name" must appear in the GROUP BY clause or be used in an aggregate function 63 | LINE 1:select count(*), create_date, first_name from Users group by... 64 | 65 | 66 | ``` 67 | 68 | This is telling us that the `first_name` column needs to be added to the `group by` in order to pull this out. Remember, our rows are being grouped together by create date. Because more than one row can be in a group, as in our January 10th example, our database doesn't know which `first_name` value to pull out of the grouping, which is why we're getting this error. 69 | 70 | If we add `first_name` to the `group by`, we no longer get this error, but instead get all four rows back. 71 | 72 | ```sql 73 | select count(*), create_date, first_name from Users group by create_date, first_name; 74 | count | create_date | first_name 75 | ----------+----------------+-------------- 76 | 1 | 2018-06-06 | tyler 77 | 1 | 2019-01-10 | patrick 78 | 1 | 2019-01-10 | mary 79 | 1 | 2019-02-01 | debbie 80 | 81 | (4 rows) 82 | 83 | 84 | ``` 85 | 86 | This is because our `group by` is now looking to create groups that share `create_date` and `first_name`. Because none of our rows share these two columns, we get all four rows out. Keeping this mentality of grouping in mind, most SQL databases have built-in aggregate functions. For example, if we wanted to find what the lowest value create date was within our table, we'd use the `min()` function. 87 | 88 | ```sql 89 | select min(create_date) from Users; 90 | min 91 | ------------ 92 | 2018-06-06 93 | (1 row) 94 | 95 | 96 | ``` 97 | 98 | Aggregate functions are closely related to grouping operations like group by, which is why we'll get the same error as we did before when trying to pull out our `first_name` column with the `min()` function. 99 | 100 | ```sql 101 | select min(create_date), first_name from Users; 102 | ERROR: column "users.first_name" must appear in the GROUP BY clause or be used in an aggregate function 103 | LINE 1:select min(create_date), first_name from Users; 104 | 105 | 106 | ``` 107 | 108 | As a side note, if you're curious on how to accomplish the task I talked about in this lesson, I'll post those two queries in the notes to this video. We need to do a little bit more than just `group by` and aggregate the `create_date` values. Some other common aggregate functions are `max()`, which does the opposite of `min()`, there's `sum()`, which sums up values, and average. 109 | 110 | ```sql 111 | select max(create_date) from Users; 112 | min 113 | ------------ 114 | 2019-02-01 115 | (1 row) 116 | 117 | 118 | ``` 119 | 120 | Be sure to check the notes to this video for links to popular SQL databases that implement these, as well as their own functions. 121 | -------------------------------------------------------------------------------- /09-conditionally-select-out-filtered-data-with-sql-where/exercises.md: -------------------------------------------------------------------------------- 1 | # Conditionally Select out Filtered Data with SQL Where Exercises 2 | 3 | ## Set up 4 |
5 | 6 |
7 | If you created a `Products` table from a previous exercise, skip this query. 8 | 9 | ```sql 10 | create table Products ( 11 | create_date date, 12 | product_id uuid, 13 | title character(50), 14 | description text, 15 | price money, 16 | technology character(50) 17 | ); 18 | ``` 19 | Insert values into table: 20 | ```sql 21 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'short React course', 'This course you will start to learn about React.', '50.00', 'react'); 22 | 23 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'React course', 'This course you will learn all about React.', '150.00', 'react'); 24 | 25 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'short Vue course', 'This course you will start to learn about Vue.', '50.00', 'vue'); 26 | 27 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Vue course', 'This course you will learn all about Vue.', '350.00', 'vue'); 28 | 29 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'short Angular course', 'This course you will start learning Angular.', '50.00', 'angular'); 30 | 31 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Angular course', 'This course you will learn all about Angular.', '450.00', 'angular'); 32 | 33 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'SQL course', 'This course you will learn all about SQL.', '550.00', 'sql'); 34 | ``` 35 |
36 | 37 | 38 | ## 1. 39 | 40 | You are looking for an intro to a few technologies. Filter for all courses with a price less than 100.00. 41 | 42 | ## 2. 43 | 44 | You're looking for a specific course. Filter for rows where `title` is equal to `SQL course` 45 | 46 | ## Extra Credit 47 | 48 | You've decided you only want to look at react courses. Filter for titles that include `React`. 49 | 50 | Hint: You might want to use [a new operator](https://stackoverflow.com/questions/14290857/sql-select-where-field-contains-words) -------------------------------------------------------------------------------- /09-conditionally-select-out-filtered-data-with-sql-where/lesson.md: -------------------------------------------------------------------------------- 1 | # Step 9 - Filtering Data 2 | 3 | ### Filter on last name 4 | ``` 5 | select create_date, last_name, first_name from Users where last_name = 'clark'; 6 | ``` 7 | 8 | ### Filter on a Date Range 9 | ``` 10 | select * from Users where create_date between '2018-05-01' and '2018-09-01'; 11 | ``` -------------------------------------------------------------------------------- /09-conditionally-select-out-filtered-data-with-sql-where/transcript.md: -------------------------------------------------------------------------------- 1 | When we use the `select` statement as is, we get everything out of our table. 2 | 3 | ```sql 4 | select * from Users; 5 | create_date | user_handle | last_name | first _name 6 | --------------+--------------------------------------+-----------+------------- 7 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 8 | 2018-06-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 9 | (2 rows ) 10 | 11 | ``` 12 | 13 | If we want to filter the results down to specific rows, we use the `where` clause. Within our `select` statement, let's say select out all the columns where the `where last_name = 'clark';`. 14 | 15 | ```sql 16 | select * from Users where last_name = 'clark'; 17 | create_date | user_handle | last_name | first _name 18 | --------------+--------------------------------------+-----------+------------- 19 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 20 | (1 row ) 21 | 22 | ``` 23 | 24 | You can think of the select statement as a for loop. We're looping over each row within the table and pulling it out. This `where` clause is how we can filter down what actually gets returned. Only having one condition within our `where` clause did the job. However, we could get more specific and add more cases. We can add on to our `where` clause an `and first_name = 'tyler'; ` to get the same row back. 25 | 26 | ```sql 27 | select * from Users where last_name = 'clark' and first_name = 'tyler'; 28 | create_date | user_handle | last_name | first _name 29 | --------------+--------------------------------------+-----------+------------- 30 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 31 | (1 row ) 32 | 33 | ``` 34 | 35 | Using the `and` logical operator means that both cases provided here have to be true for any rows to be returned. We could instead use the `or` logical operator as well, which means that at least one of the two cases needs to be true. 36 | 37 | ```sql 38 | select * from Users where last_name = 'clark' or first_name = 'tyler'; 39 | create_date | user_handle | last_name | first _name 40 | --------------+--------------------------------------+-----------+------------- 41 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 42 | (1 row ) 43 | 44 | ``` 45 | 46 | When working with dates and numbers, we can use other operators such as the `>`, say, give us the rows `where create_date > '2018-05-05';`, which is going to be both rows. 47 | 48 | ```sql 49 | select * from Users where create_date > '2018-05-05'; 50 | create_date | user_handle | last_name | first _name 51 | --------------+--------------------------------------+-----------+------------- 52 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 53 | 2018-06-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 54 | 55 | (2 rows ) 56 | 57 | ``` 58 | 59 | We can use the `<`, which will give us neither of the two rows. 60 | 61 | ```sql 62 | select * from Users where create_date < '2018-05-05'; 63 | create_date | user_handle | last_name | first _name 64 | --------------+--------------------------------------+-----------+------------- 65 | (0 rows ) 66 | 67 | ``` 68 | 69 | As well as `=`, which again will give us neither. 70 | 71 | ```sql 72 | select * from Users where create_date < '2018-05-05'; 73 | create_date | user_handle | last_name | first _name 74 | --------------+--------------------------------------+-----------+------------- 75 | (0 rows ) 76 | 77 | ``` 78 | 79 | There is `>=`, which will give us back our two rows, because they're greater than May 5th. 80 | 81 | ```sql 82 | select * from Users where create_date >= '2018-05-05'; 83 | create_date | user_handle | last_name | first _name 84 | --------------+--------------------------------------+-----------+------------- 85 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 86 | 2018-06-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 87 | 88 | (2 rows ) 89 | 90 | ``` 91 | 92 | There's the `<=`, which is none. 93 | 94 | ```sql 95 | select * from Users where create_date <= '2018-05-05'; 96 | create_date | user_handle | last_name | first _name 97 | --------------+--------------------------------------+-----------+------------- 98 | (0 rows ) 99 | 100 | ``` 101 | 102 | Finally, the not equal, `<>`, which is going to give us our rows, because both rows have a create date that's not equal to May 5th. 103 | 104 | ```sql 105 | select * from Users where create_date <> '2018-05-05'; 106 | create_date | user_handle | last_name | first _name 107 | --------------+--------------------------------------+-----------+------------- 108 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 109 | 2018-06-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 110 | 111 | (2 rows ) 112 | ``` 113 | 114 | There are a couple of other special operators as well. I'm going to `insert` a row into our table that has no `last_name` and `first_name`, as well as a different create date value. 115 | 116 | ```sql 117 | insert into Users values ('2018-08-06', uuid_generate_v4()); 118 | INSERT 0 1 119 | select * from Users; 120 | create_date | user_handle | last_name | first _name 121 | --------------+--------------------------------------+-----------+------------- 122 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 123 | 2018-06-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 124 | 2018-08-06 | fw1kv3z4-fk98-pl2f-se48-f823jfhaj39f | | 125 | (3 rows ) 126 | ``` 127 | 128 | With this in there, we can say select out the rows `where first_name is null;`. This is going to give us that one row. 129 | 130 | ```sql 131 | select * from Users where first_name is null; 132 | create_date | user_handle | last_name | first _name 133 | --------------+--------------------------------------+-----------+------------- 134 | 2018-08-06 | fw1kv3z4-fk98-pl2f-se48-f823jfhaj39f | | 135 | (1 row ) 136 | ``` 137 | 138 | When working with null values, which signify unknown, we cannot use the `=` sign, because it will return null itself, not a true or false value. 139 | 140 | ```sql 141 | select * from Users where first_name = null; 142 | create_date | user_handle | last_name | first _name 143 | --------------+--------------------------------------+-----------+------------- 144 | (0 rows ) 145 | ``` 146 | 147 | We have to use this `is` operator. Another for operator is `between`. Say `select * from Users where create_date between '2018-05-01' and '2018-09-01';`. This is going to give us all three rows, because the create date falls between this range. 148 | 149 | ```sql 150 | select * from Users where create_date between '2018-05-01' and '2018-09-01'; 151 | create_date | user_handle | last_name | first _name 152 | --------------+--------------------------------------+-----------+------------- 153 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 154 | 2018-06-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 155 | 2018-08-06 | fw1kv3z4-fk98-pl2f-se48-f823jfhaj39f | | 156 | (3 rows ) 157 | ``` 158 | 159 | We can exclude the August date by changing the last range to end July 1st. 160 | 161 | ```sql 162 | select * from Users where create_date between '2018-05-01' and '2018-07-01'; 163 | create_date | user_handle | last_name | first _name 164 | --------------+--------------------------------------+-----------+------------- 165 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 166 | 2018-06-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 167 | (2 rows ) 168 | ``` 169 | 170 | Finally, there is the `in` operator, which gives us all the rows where the `last_name` column equals any of the values within this list. The list is separated by commas and we can work with strings and numbers within these parenthesis. 171 | 172 | ```sql 173 | select * from Users where last_name in ('clark', 'jones'); 174 | create_date | user_handle | last_name | first _name 175 | --------------+--------------------------------------+-----------+------------- 176 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 177 | 2018-06-06 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 178 | (2 rows ) 179 | ``` 180 | 181 | As we see here, we did not get that third row, which had no values for the `last_name` and `first_name` columns. -------------------------------------------------------------------------------- /10-combining-tables-together-with-sql-join-statements/exercises.md: -------------------------------------------------------------------------------- 1 | # Combining Tables Together with SQL Join Statements Exercises 2 | 3 | ## Set up 4 | It is important for these exercises that the id's (`user_handle` and `product_id`) match for the data that is put into the `Purchases` table. If you have data in your `Users` and `Products` already, you can delete that data and use what is provided below or grab the id's that you have set (they need to be unique). 5 | 6 | Note: Purchase data available at the bottom of details section. 7 |
8 | If data exists in the `Users` and `Products` tables: 9 | ```sql 10 | truncate Products; 11 | truncate Users; 12 | ``` 13 | 14 |
15 | ```sql 16 | create table Users ( 17 | create_date date, 18 | user_handle uuid, 19 | last_name text, 20 | first_name text 21 | ); 22 | ``` 23 | ```sql 24 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', '4ff119f0-91b1-4020-8005-69bf0dd8b492', 'clark', 'tyler'); 25 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', 'jones', 'debbie'); 26 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', '3bd67317-0efa-48c9-914c-42234072d94b', 'freemon', 'mary'); 27 | ``` 28 | 29 | ```sql 30 | create table Products ( 31 | create_date date, 32 | product_id uuid, 33 | title character(50), 34 | description text, 35 | price money, 36 | technology character(50) 37 | ); 38 | ``` 39 | Insert values into table: 40 | ```sql 41 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'short React course', 'This course you will start to learn about React.', '50.00', 'react'); 42 | 43 | insert into Products values (now(), '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 'React course', 'This course you will learn all about React.', '150.00', 'react'); 44 | 45 | insert into Products values (now(), '13e55094-00d5-4c9b-bd8e-ce38072ae551', 'short Vue course', 'This course you will start to learn about Vue.', '50.00', 'vue'); 46 | 47 | insert into Products values (now(), '562951b6-3648-42fd-b49e-156c6a7edf60', 'Vue course', 'This course you will learn all about Vue.', '350.00', 'vue'); 48 | 49 | insert into Products values (now(), '18c299a8-772a-424b-841e-f3d082019271', 'short Angular course', 'This course you will start learning Angular.', '50.00', 'angular'); 50 | 51 | insert into Products values (now(), '40c88e1e-0910-4017-9b6f-12337e22183a', 'Angular course', 'This course you will learn all about Angular.', '450.00', 'angular'); 52 | 53 | insert into Products values (now(), '75f9eaba-136e-4b79-9579-5fd47b48797f', 'SQL course', 'This course you will learn all about SQL.', '550.00', 'sql'); 54 | ``` 55 | 56 | ```sql 57 | create table Purchases (date date, user_handle uuid, sku uuid, quantity int); 58 | ``` 59 | 60 | ```sql 61 | insert into Purchases values ('2019-04-22', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '75f9eaba-136e-4b79-9579-5fd47b48797f', 1); 62 | insert into Purchases values ('2019-11-23', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '40c88e1e-0910-4017-9b6f-12337e22183a', 3); 63 | insert into Purchases values ('2019-07-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '13e55094-00d5-4c9b-bd8e-ce38072ae551', 1); 64 | insert into Purchases values ('2019-09-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 2); 65 | insert into Purchases values ('2019-05-23', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', '75f9eaba-136e-4b79-9579-5fd47b48797f', 6); 66 | insert into Purchases values ('2019-11-02', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', '40c88e1e-0910-4017-9b6f-12337e22183a', 4); 67 | insert into Purchases values ('2019-04-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '40c88e1e-0910-4017-9b6f-12337e22183a', 2); 68 | insert into Purchases values ('2019-11-02', '3bd67317-0efa-48c9-914c-42234072d94b', '75f9eaba-136e-4b79-9579-5fd47b48797f', 7); 69 | insert into Purchases values ('2019-02-02', '3bd67317-0efa-48c9-914c-42234072d94b', '562951b6-3648-42fd-b49e-156c6a7edf60', 1); 70 | insert into Purchases values ('2019-04-23', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 1); 71 | insert into Purchases values ('2019-04-02', '3bd67317-0efa-48c9-914c-42234072d94b', '18c299a8-772a-424b-841e-f3d082019271', 4); 72 | insert into Purchases values ('2019-11-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '562951b6-3648-42fd-b49e-156c6a7edf60', 1); 73 | insert into Purchases values ('2019-10-23', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 3); 74 | insert into Purchases values ('2019-04-12', '3bd67317-0efa-48c9-914c-42234072d94b', '13e55094-00d5-4c9b-bd8e-ce38072ae551', 1); 75 | insert into Purchases values ('2019-02-15', '3bd67317-0efa-48c9-914c-42234072d94b', '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 2); 76 | ``` 77 |
78 | 79 | 80 | ## 1. 81 | Find all the `Products` that have been purchased and display the `title` and `date` of purchase 82 | 83 | 84 | ## 2. 85 | 86 | Find all `Products` that were purchased before `2019-06-15` with the `title`, `date`, and `quantity` displayed. 87 | 88 | ## 3. 89 | 90 | Consider the [Postgres Table Expressions documentations](https://www.postgresql.org/docs/current/queries-table-expressions.html) and explore how you can join the tables you have created so far together. -------------------------------------------------------------------------------- /10-combining-tables-together-with-sql-join-statements/lesson.md: -------------------------------------------------------------------------------- 1 | # Step 10 - Joining Tables 2 | 3 | 4 | ### Create a new table 5 | ```sql 6 | create table Purchases (date date, user_handle uuid, sku uuid, quantity int); 7 | ``` 8 | 9 | ### Create a row of data with user_handle 10 | ```sql 11 | insert into Purchases (date, user_handle, sku, quantity) values ('2018-12-12', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', uuid_generate_v4(), 2); 12 | ``` 13 | 14 | ### Combine the User and Purchases table user handles 15 | ```sql 16 | select * from Users u left outer join Purchases p on u.user_handle = p.user_handle; 17 | ``` 18 | 19 | ### Create a row of data with random id's 20 | ```sql 21 | insert into Purchases values ('2019-02-02', uuid_generate_v4(), uuid_generate_v4(), 1); 22 | ``` 23 | 24 | ### Cross join the Users and Purchases table 25 | ```sql 26 | select * from Users u cross join Purchases p; 27 | ``` 28 | 29 | ### Combine the User and Purchases table emails 30 | ```sql 31 | select * from Users u left outer join Purchases ua on u.email = ua.email; 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /10-combining-tables-together-with-sql-join-statements/transcript.md: -------------------------------------------------------------------------------- 1 | If this is the first time getting your hands dirty with SQL and databases, you might find yourself thinking that your tables need to hold as many columns that are relevant as possible. For example, when dealing with `Users`, as in our case, we could add more columns for email, address, phone number for each person, and then gone even deeper with their user history, like if they've changed their email from what to what, and then a column for when that happened. 2 | 3 | ```sql 4 | select * from Users; 5 | create_date | user_handle | last_name | first _name 6 | --------------+--------------------------------------+-----------+------------- 7 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 8 | 2019-02-01 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 9 | 2010-01-10 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | freemon | mary 10 | (3 rows) 11 | ``` 12 | 13 | Before long, you'll find that your table has too many columns to keep track of. Eventually, this one table will have to deal with a lot of transactions at the same time, especially, as you scale your application. Instead, we want to keep our tables simple and modular. We have our users table with three users. I've also gone ahead and created a `Purchases` table that has two rows of data. 14 | 15 | ```sql 16 | select * from Purchases; 17 | date | user_handle | sku | quality 18 | --------------+--------------------------------------+------------------------------------------+------------- 19 | 2018-12-12 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | f82jkfhs-al4e-cmn3-f98c-jhub42kvogj5 | 2 20 | 2019-02-02 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 1 21 | (2 rows) 22 | ``` 23 | 24 | Each one of these rows represents a purchase that someone from our `Users` table made. Let's say that we were making a dashboard within our application that displayed the user's information as well as their purchase history, which is really common. We could make two separate calls to our database to get this info, one, to get all the info about the user and the other, to get all of their purchases. Instead what we can do is get it all out in one query by joining these two tables together. In our first example, we'll use the `left outer join`. 25 | 26 | ```sql 27 | select * from Users u left outer join Purchases p on u.user_handle = p.user_handle; 28 | create_date | user_handle | last_name | first _name | date | user_handle | sku | quantity 29 | --------------+-------------------------------------+-----------+--------------+------------+--------------------------------------+--------------------------------------+----------------- 30 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler | 2018-12-12 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | f82jkfhs-al4e-cmn3-f98c-jhub42kvogj5 | 2 31 | 2019-02-01 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | freemon | mary | 2019-02-02 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 1 32 | 2010-01-10 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | jones | debbie 33 | (3 rows) 34 | ``` 35 | 36 | Now let's walk through what's happening here. We still use the `select *` which will pull out all of our columns returned from the rest of our query. We say from our `Users` table, and this `u` is aliasing the `Users` table, kind of like making it a variable that we can reference throughout the rest of this query. We then say `left outer join` with the `Purchases` table aliased as `p`, on the matching `u.user_handle` between the two tables. 37 | 38 | Now let's get more into the `join`. You'll see that we now have our two tables' columns added together to form one large table. All of the users columns are accounted for, as well as purchases. You can see we have two user handle columns because they're both shared. When joining tables together, we tell it what condition to join on. This is why we need the `on` statement in our query, so our tables know where to fuse. You'll notice that `Debbie` does not have any purchases, so all the columns are holding the NULL value for each of her purchase columns. `left outer join` is saying, "Get the table and all of its rows stated to the left of the join statement," in our case, `Users`, as our starting set of data. With this data, match it up with the following purchases table rows, filling in NULL values for any missing rows, which again is why Debbie's purchase columns has null values, because she doesn't have a row in purchases. 39 | 40 | Now let's change our `left outer join` to be a `right outer join`, and we'll see what we get. 41 | 42 | ```sql 43 | select * from Users u right outer join Purchases p on u.user_handle = p.user_handle; 44 | create_date | user_handle | last_name | first _name | date | user_handle | sku | quality 45 | --------------+-------------------------------------+-----------+--------------+------------+--------------------------------------+--------------------------------------+----------------- 46 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler | 2018-12-12 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | f82jkfhs-al4e-cmn3-f98c-jhub42kvogj5 | 2 47 | 2019-02-01 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | freemon | mary | 2019-02-02 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 1 48 | (2 rows) 49 | ``` 50 | 51 | We have to zoom way out to see everything. Now with our `right outer join`, we're not starting with a users dataset first. We take the right table's data. In our case, the two `Purchases` table rows and match up the `Users` rows with them. We start with two rows, and that's what we end up with in the end. As you can see, Debbie doesn't show up in this list, because she's not in the purchases table. 52 | 53 | Now let's `insert` a row into our purchases table and have it generate a random user handle that does not exist in our users table. 54 | 55 | ```sql 56 | insert into Purchases values ('2019-02-02', uuid_generate_v4(), uuid_generate_v4(), 1); 57 | INSERT 01 58 | ``` 59 | 60 | We'll rerun our `join` statement and see that because there's no matching user handle for this newly inserted row that matches our `Users` table, we fill in NULL values for the users table data columns. 61 | 62 | ```sql 63 | select * from Users u right outer join Purchases p on u.user_handle = p.user_handle; 64 | create_date | user_handle | last_name | first _name | date | user_handle | sku | quality 65 | --------------+-------------------------------------+-----------+--------------+------------+--------------------------------------+--------------------------------------+----------------- 66 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler | 2018-12-12 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | f82jkfhs-al4e-cmn3-f98c-jhub42kvogj5 | 2 67 | 2019-02-01 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | freemon | mary | 2019-02-02 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 1 68 | | | | | 2019-02-02 | pha93nc4-p2l4-cn9x-fn10-fn2kgph82zx4 | 0oqm38fb-fm18-fh2k-3nvo-23hgk4nehvsl | 1 69 | (3 rows) 70 | ``` 71 | 72 | What if we want both missing rows of data in our combined ultimate table? We want to see Debbie in here, as well as this `Purchases` row that does not have a matching `User`. We do that by using the `full outer join` statement. 73 | 74 | ```sql 75 | select * from Users u full outer join Purchases p on u.user_handle = p.user_handle; 76 | create_date | user_handle | last_name | first _name | date | user_handle | sku | quality 77 | --------------+-------------------------------------+-----------+--------------+------------+--------------------------------------+--------------------------------------+----------------- 78 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler | 2018-12-12 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | f82jkfhs-al4e-cmn3-f98c-jhub42kvogj5 | 2 79 | 2019-02-01 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | freemon | mary | 2019-02-02 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 1 80 | | | | | 2019-02-02 | pha93nc4-p2l4-cn9x-fn10-fn2kgph82zx4 | 0oqm38fb-fm18-fh2k-3nvo-23hgk4nehvsl | 1 81 | 2010-01-10 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | jones | debbie 82 | (4 rows) 83 | ``` 84 | 85 | The result is we have four total rows with NULL values inserted for missing columns on both sides. 86 | 87 | There's also `inner join`, which is the opposite of `full outer join`. 88 | 89 | ```sql 90 | select * from Users u inner join Purchases p on u.user_handle = p.user_handle; 91 | create_date | user_handle | last_name | first _name | date | user_handle | sku | quality 92 | --------------+-------------------------------------+-----------+--------------+------------+--------------------------------------+--------------------------------------+----------------- 93 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler | 2018-12-12 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | f82jkfhs-al4e-cmn3-f98c-jhub42kvogj5 | 2 94 | 2019-02-01 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | freemon | mary | 2019-02-02 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 1 95 | (2 rows) 96 | ``` 97 | 98 | It only returns an ultimate joined table, where there's a matching `user_handle` on both tables. Finally, there's `cross join`, which doesn't take a join on statement, because it takes the first table's rows and assigns it each row of the joining purchases table. 99 | 100 | ```sql 101 | select * from Users u cross join Purchases p; 102 | create_date | user_handle | last_name | first _name | date | user_handle | sku | quality 103 | --------------+-------------------------------------+-----------+--------------+------------+--------------------------------------+--------------------------------------+----------------- 104 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler | 2018-12-12 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | f82jkfhs-al4e-cmn3-f98c-jhub42kvogj5 | 2 105 | 2019-02-01 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | jones | debbie | 2018-12-12 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | f82jkfhs-al4e-cmn3-f98c-jhub42kvogj5 | 2 106 | 2010-01-10 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | freemon | mary | 2018-12-12 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | f82jkfhs-al4e-cmn3-f98c-jhub42kvogj5 | 2 107 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler | 2019-02-02 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 1 108 | 2019-02-01 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | jones | debbie | 2019-02-02 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 1 109 | 2010-01-10 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | freemon | mary | 2019-02-02 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 1 110 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler | 2019-02-02 | pha93nc4-p2l4-cn9x-fn10-fn2kgph82zx4 | 0oqm38fb-fm18-fh2k-3nvo-23hgk4nehvsl | 1 111 | 2019-02-01 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | jones | debbie | 2019-02-02 | pha93nc4-p2l4-cn9x-fn10-fn2kgph82zx4 | 0oqm38fb-fm18-fh2k-3nvo-23hgk4nehvsl | 1 112 | 2010-01-10 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | freemon | mary | 2019-02-02 | pha93nc4-p2l4-cn9x-fn10-fn2kgph82zx4 | 0oqm38fb-fm18-fh2k-3nvo-23hgk4nehvsl | 1 113 | (9 rows) 114 | ``` 115 | 116 | As you can see, I'm in here three times because the purchases table has three rows of data. My `Users` row is duplicated and matched up with each row in `Purchases`, which is why cross join doesn't accept any on conditions. 117 | 118 | There are a couple of final points to know when working with joins. If we specifically ask for a column that is shared between two joining tables, we'll get an error asking us which column from which table to pull out. 119 | 120 | ```sql 121 | select user_handle from Users u inner join Purchases p on u.user_handle = p.user_handle; 122 | ERROR: column reference "user_handle" is ambiguous 123 | LINE 1: select user_handle from Users u inner join Purchases p on u.... 124 | ``` 125 | 126 | This is why we need to alias our tables, so that we can specify which table column combination we want to pull out. 127 | 128 | ```sql 129 | select user_handle from Users u inner join Purchases p on u.user_handle = p.user_handle; 130 | ---------------------------------- 131 | 2839f831-f82c-faj3-aof3-fj28ddks39ek 132 | f82jkfhs-al4e-cmn3-f98c-jhub42kvogj5 133 | (2 rows) 134 | ``` 135 | 136 | Another tidbit is we only had one join on clause. You can add more conditions by using `and`. 137 | -------------------------------------------------------------------------------- /11-subquery-dynamic-datasets-in-sql/exercises.md: -------------------------------------------------------------------------------- 1 | # Subquery Dynamic Datasets in SQL Exercises 2 | ## Set up 3 |
4 | If data exists in the `Users` and `Products` tables: 5 | ```sql 6 | truncate Products; 7 | truncate Users; 8 | ``` 9 | 10 |
11 | ```sql 12 | create table Users ( 13 | create_date date, 14 | user_handle uuid, 15 | last_name text, 16 | first_name text 17 | ); 18 | ``` 19 | ```sql 20 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', '4ff119f0-91b1-4020-8005-69bf0dd8b492', 'clark', 'tyler'); 21 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', 'jones', 'debbie'); 22 | insert into Users (create_date, user_handle, last_name, first_name ) values ('2018-06-06', '3bd67317-0efa-48c9-914c-42234072d94b', 'freemon', 'mary'); 23 | ``` 24 | 25 | ```sql 26 | create table Products ( 27 | create_date date, 28 | product_id uuid, 29 | title character(50), 30 | description text, 31 | price money, 32 | technology character(50) 33 | ); 34 | ``` 35 | Insert values into table: 36 | ```sql 37 | insert into Products values (now(), 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'short React course', 'This course you will start to learn about React.', '50.00', 'react'); 38 | 39 | insert into Products values (now(), '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 'React course', 'This course you will learn all about React.', '150.00', 'react'); 40 | 41 | insert into Products values (now(), '13e55094-00d5-4c9b-bd8e-ce38072ae551', 'short Vue course', 'This course you will start to learn about Vue.', '50.00', 'vue'); 42 | 43 | insert into Products values (now(), '562951b6-3648-42fd-b49e-156c6a7edf60', 'Vue course', 'This course you will learn all about Vue.', '350.00', 'vue'); 44 | 45 | insert into Products values (now(), '18c299a8-772a-424b-841e-f3d082019271', 'short Angular course', 'This course you will start learning Angular.', '50.00', 'angular'); 46 | 47 | insert into Products values (now(), '40c88e1e-0910-4017-9b6f-12337e22183a', 'Angular course', 'This course you will learn all about Angular.', '450.00', 'angular'); 48 | 49 | insert into Products values (now(), '75f9eaba-136e-4b79-9579-5fd47b48797f', 'SQL course', 'This course you will learn all about SQL.', '550.00', 'sql'); 50 | ``` 51 | 52 | ```sql 53 | create table Purchases (date date, user_handle uuid, sku uuid, quantity int); 54 | ``` 55 | 56 | ```sql 57 | insert into Purchases values ('2019-04-22', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '75f9eaba-136e-4b79-9579-5fd47b48797f', 1); 58 | insert into Purchases values ('2019-11-23', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '40c88e1e-0910-4017-9b6f-12337e22183a', 3); 59 | insert into Purchases values ('2019-07-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '13e55094-00d5-4c9b-bd8e-ce38072ae551', 1); 60 | insert into Purchases values ('2019-09-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 2); 61 | insert into Purchases values ('2019-05-23', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', '75f9eaba-136e-4b79-9579-5fd47b48797f', 6); 62 | insert into Purchases values ('2019-11-02', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', '40c88e1e-0910-4017-9b6f-12337e22183a', 4); 63 | insert into Purchases values ('2019-04-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '40c88e1e-0910-4017-9b6f-12337e22183a', 2); 64 | insert into Purchases values ('2019-11-02', '3bd67317-0efa-48c9-914c-42234072d94b', '75f9eaba-136e-4b79-9579-5fd47b48797f', 7); 65 | insert into Purchases values ('2019-02-02', '3bd67317-0efa-48c9-914c-42234072d94b', '562951b6-3648-42fd-b49e-156c6a7edf60', 1); 66 | insert into Purchases values ('2019-04-23', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 1); 67 | insert into Purchases values ('2019-04-02', '3bd67317-0efa-48c9-914c-42234072d94b', '18c299a8-772a-424b-841e-f3d082019271', 4); 68 | insert into Purchases values ('2019-11-02', '4ff119f0-91b1-4020-8005-69bf0dd8b492', '562951b6-3648-42fd-b49e-156c6a7edf60', 1); 69 | insert into Purchases values ('2019-10-23', '6ab3b2d2-8e02-890c-bb6d-61a67cd43f31', '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 3); 70 | insert into Purchases values ('2019-04-12', '3bd67317-0efa-48c9-914c-42234072d94b', '13e55094-00d5-4c9b-bd8e-ce38072ae551', 1); 71 | insert into Purchases values ('2019-02-15', '3bd67317-0efa-48c9-914c-42234072d94b', '5a2a8657-60d6-4d67-ac34-28f9a47a71d3', 2); 72 | ``` 73 |
74 | 75 | ## 1. (video challenge) 76 | ```sql 77 | select user_handle, sku, (select avg(quantity) from Purchases) from Purchases; 78 | ``` 79 | 80 | This query gives a consistent average across all of the quantities within the `Purchases` table. 81 | 82 | Find the averge of all purchases relative to the user. 83 | 84 | ## 2. 85 | 86 | Use Subqerries to return how many of each individual coruse in `Products` was purchased. 87 | 88 | -------------------------------------------------------------------------------- /11-subquery-dynamic-datasets-in-sql/lesson.md: -------------------------------------------------------------------------------- 1 | # Step 11 - Subqueries 2 | ```sql 3 | select create_date, first_name from Users where create_date = (select min(create_date) from Users); 4 | ``` 5 | 6 | or 7 | 8 | ```sql 9 | select u.total, u.create_date, first_name from Users us inner join (select count(create_date) as total, create_date from Users group by create_date) u on u.create_date = us.create_date; 10 | ``` 11 | 12 | ### Average between all purchases within the Purchases table 13 | ```sql 14 | select user_handle, sku, (select avg(quantity) from Purchases) from Purchases; 15 | ``` 16 | 17 | ### Return the first created User 18 | ```sql 19 | select create_date, first_name from Users where create_date = (select min(create_date) from Users); 20 | ``` 21 | -------------------------------------------------------------------------------- /11-subquery-dynamic-datasets-in-sql/transcript.md: -------------------------------------------------------------------------------- 1 | One of my personal favorite aspects of SQL is the ability to write queries within a query. This composability makes it easier to pull out intended data all in one call rather than making multiple calls and getting data out in pieces. 2 | 3 | ```sql 4 | select * from Users; 5 | create_date | user_handle | last_name | first _name 6 | --------------+--------------------------------------+-----------+------------- 7 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | tyler 8 | 2019-02-01 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 9 | 2010-01-10 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | freemon | mary 10 | (3 rows) 11 | ``` 12 | 13 | In the grouping and lesson within this course, we wanted to pull out the row that had the earliest `create_date`. If we do `select min(create_date)`, and then pull out the `first_name`, we get an error. 14 | 15 | ```sql 16 | select min(create_date), first_name from Users; 17 | ERROR: column "users.first_name" must appear in the GROUP BY clause or be used in an aggregate function 18 | LINE 1: select min(create_date). first_name from Users; 19 | ``` 20 | 21 | Our database doesn't know how to handle the other columns while it's aggregating all the `create_date` columns down to one. If we add `first_name` to the `group by`, we see we get all three rows out, because now that `first_name` is grouped by unique first names, we'll get out the man per grouping of first names. 22 | 23 | ```sql 24 | select min(create_date), first_name from Users group by first_name; 25 | 26 | min | first_name 27 | ------------+------------ 28 | 2018-06-06 | tyler 29 | 2019-02-01 | debbie 30 | 2019-01-10 | mary 31 | (3 rows) 32 | ``` 33 | 34 | Instead, what we want to do is use a subquery. For that, we'll write, `select create_date, first_name from Users where create_date` equals a subquery, selecting out the `(select min(create_date) from Users);` table. 35 | 36 | ```sql 37 | select create_date, first_name from Users where create_date = (select min(create_date) from Users); 38 | 39 | min | first_name 40 | ------------+------------ 41 | 2018-06-06 | tyler 42 | (1 row) 43 | ``` 44 | 45 | You see that this returns my name for `first_name` and my `create_date`. In order to use a subquery, it needs to be wrapped in parenthesis. Our subquery here returns one man `create_date` from our `Users` table. 46 | 47 | That's what we use to filter by, where our `min` from the inner query matches the `create_date` from the outer query. With this filter matching on the correct row, we can just pull out all the columns then. Subqueries can be used in other commands such as `insert`, `update`, and `delete`. Let's update the `first_name` column of the row that has the earliest `create_date` to `'danny'`. 48 | 49 | ```sql 50 | update Users set first_name = 'danny' where create_date = (select min(create_date) from Users); 51 | UPDATE 1 52 | ``` 53 | ```sql 54 | select * from Users; 55 | create_date | user_handle | last_name | first _name 56 | --------------+--------------------------------------+-----------+------------- 57 | 2019-02-01 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | jones | debbie 58 | 2010-01-10 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | freemon | mary 59 | 2018-06-06 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | clark | danny 60 | (3 rows) 61 | ``` 62 | 63 | Here you'll see that we've changed from Tyler to Danny. Not only can subqueries be used as a way to filter, but we can use them as a table to join on. Let's write, `select total, first_name from Users us inner join` on a subquery. We'll do `(select count(user_handle) as total, user_handle from Purchases group by user_handle)`, and then we'll say where user handles match, `p.user_handle = us.user_handle;`. 64 | 65 | ```sql 66 | select total, first_name from Users us inner join (select count(user_handle) as total, user_handle from Purchases group by user_handle) p on p.user_handle = us.user_handle; 67 | total | first_name 68 | ------------+------------ 69 | 1 | danny 70 | 2 | mary 71 | (2 rows) 72 | ``` 73 | 74 | With this in place, we'll see that Danny had one purchase and Mary had two purchases from the `Purchases` table. Let's walk through this again. The top-level query is going to give us one column that exists on users, and the other that we create from our subquery. Our subquery is getting a count of group by user handles. 75 | 76 | This count tells us how many rows are in each group `user_handle`. We `inner join` on the `user_handle`. We pull out from the subquery and the user handles that already exist on the `Users` table. The returning results show us how many orders each person purchased. 77 | 78 | Another option is using subqueries as a column value. For example, I want to return the average order size along with all of my `sku`'s and user handles inside of my `Purchases` table. I can add a subquery next to my other columns. 79 | 80 | ```sql 81 | select user_handle, sku, (select avg(quantity) from Purchases) from Purchases; 82 | user_handle | sku | avg 83 | --------------------------------------+---------------------------------------+--------------- 84 | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | 1.50000000000 85 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | a0eebc99-9c0b-42f8-bb6d-6bb9bd380a11 | 1.50000000000 86 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | a0eebc99-9c0b-42f8-bb6d-6bb9bd380a11 | 1.50000000000 87 | a0eebc99-9c0b-42f8-g3eh-6bb9bd380a11 | 2839f831-f82c-faj3-aof3-fj28ddks39ek | 1.50000000000 88 | (4 rows) 89 | ``` 90 | 91 | When I run this, I get all of my `user_handle`'s, all of my `sku`'s, and a consistent average across all of the quantities within the `Purchases` table. 92 | 93 | To clarify, this isn't stating that the average for this user for the `sku` is this value. This is just the average quantity for all of the purchases made inside of our `Purchases` table. I will, though, post the solution for making this average be a reflection of this user handle and the skew in the notes. 94 | 95 | Before you look, see if you can do it yourself. You'll want to enter another row with the same `user_handle` and `sku` and a different quantity to make sure it's working like it should. 96 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 1.0.0 9 | 10 | ### Added 11 | 12 | - This file. 13 | - All lessons as monorepo. 14 | - exercises, lesson, solutions, and transcript files for each lesson folder 15 | - Add `postgresql#11.2`. 16 | 17 | ### Changed 18 | 19 | - Update README to describe repository 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [SQL Fundamentals](https://egghead.io/courses/sql-fundamentals) 2 | 3 | This repo contains exercises and supplementary content for Tyler Clarks [SQL Fundamentals](https://egghead.io/courses/sql-fundamentals) course. 4 | 5 | Each lesson is divided into it's own folder with the commands Tyler ran in the related lesson, transcripts for the lesson, as well as exercises to complete (and subsequent solution in a separate file). 6 | 7 | -------------------------------------------------------------------------------- /solutions/01-create-a-table-with-sql-create-solutions.md: -------------------------------------------------------------------------------- 1 | # Create a Table with SQL Create Solution 2 | 3 | ### Product Table 4 | ```sql 5 | create table Products ( 6 | create_date date, 7 | product_id uuid, 8 | title character(50), 9 | description text, 10 | price money 11 | ); 12 | ``` 13 | To verify this works, add a product to the `Products` table with the `insert` command bellow: 14 | 15 | ```sql 16 | insert into Products (create_date, product_id, title, description, price) values ('2018-06-06', 'b1debc99-9c0b-4ef8-bb6d-6bb9ac380bb1', 'sql course', 'This course is designed to take someone that has no experience with relational databases and teach them how to at least create, read, update, and delete.', '100.00'); 17 | ``` 18 | 19 | And return all products from the table: 20 | ```sql 21 | select * from Products; 22 | ``` 23 | 24 | This should produce output similar to: 25 | 26 | | create_date | product_id | title | description | price | 27 | | ------------------------ | ------------------------------------ | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | 28 | | 2018-06-06T00:00:00.000Z | b1debc99-9c0b-4ef8-bb6d-6bb9ac380bb1 | sql course | This course is designed to take someone that has no experience with relational databases and teach them how to at least create, read, update, and delete. | $100.00 | 29 | 30 | --- -------------------------------------------------------------------------------- /solutions/02-add-data-to-a-table-with-sql-insert-solutions.md: -------------------------------------------------------------------------------- 1 | # Add Data to a Table with SQL Insert 2 | 3 | ## 1. Add Static Data 4 | 5 | ### Query 6 | ```sql 7 | insert into Products (create_date, product_id, title, description, price, technology) values ('2018-06-06', 'b1debc99-9c0b-4ef8-bb6d-6bb9ac380bb1', 'sql fundamentals course', 'This course is designed to take someone that has no experience with relational databases and teach them how to at least create, read, update, and delete.', '100.00', 'sql'); 8 | ``` 9 | ### Output 10 | | create_date | product_id | title | description | price | technology | 11 | | ------------------------ | ------------------------------------ | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -------------------------------------------------- | 12 | | 2018-06-06T00:00:00.000Z | b1debc99-9c0b-4ef8-bb6d-6bb9ac380bb1 | sql fundamentals course | This course is designed to take someone that has no experience with relational databases and teach them how to at least create, read, update, and delete. | $100.00 | sql | 13 | 14 | --- 15 | 16 | ## 2. Add Dynamic Data 17 | 18 | ### Query 19 | ```sql 20 | insert into Products (create_date, product_id, title, description, price) values (now(), uuid_generate_v4(), 'react course', 'This course you will learn all about React.', '250.00'); 21 | ``` 22 | 23 | or Shorthand: 24 | 25 | ```sql 26 | insert into Products values (now(), uuid_generate_v4(), 'react course', 'This course you will learn all about React.', '250.00', 'react'); 27 | ``` 28 | 29 | ### Output 30 | Something similar to: 31 | 32 | | create_date | product_id | title | description | price | technology | 33 | | ------------------------ | ------------------------------------ | -------------------------------------------------- | ------------------------------------------- | ------- | -------------------------------------------------- | 34 | | 2019-04-12T00:00:00.000Z | 49a24487-478e-4007-b204-3f924b087923 | react course | This course you will learn all about React. | $250.00 | react | 35 | 36 | --- -------------------------------------------------------------------------------- /solutions/03-query-data-with-the-select-command-in-sql-solutions.md: -------------------------------------------------------------------------------- 1 | # Query Data with the Select Command in SQL Solutions 2 | 3 | ## 1. 4 | ```sql 5 | select * from Products; 6 | ``` 7 | | create_date | product_id | title | description | price | 8 | | ------------------------ | ------------------------------------ | -------------------------------------------------- | ------------------------------------------- | ------- | 9 | | 2019-04-10T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | React course | This course you will learn all about React. | $150.00 | 10 | | 2019-04-10T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | Vue course | This course you will learn all about Vue. | $350.00 | 11 | | 2019-04-10T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | Angular course | This course you will learn all about Angular. | $450.00 | 12 | | 2019-04-10T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | SQL course | This course you will learn all about SQL. | $550.00 | 13 | 14 | --- 15 | 16 | ## 2. 17 | ```sql 18 | select count(*) from Products; 19 | ``` 20 | | count | 21 | | ----- | 22 | | 4 | 23 | 24 | --- 25 | 26 | ## 3. 27 | ```sql 28 | select title from Products; 29 | ``` 30 | | title | 31 | | -------------------------------------------------- | 32 | | React course | 33 | | Vue course | 34 | | Angular course | 35 | | SQL course | 36 | 37 | --- 38 | -------------------------------------------------------------------------------- /solutions/04-update-data-in-a-table-with-sql-update-solutions.md: -------------------------------------------------------------------------------- 1 | # Update Data in a Table with SQL Update Solutions 2 | 3 | ## 1. 4 | ```sql 5 | update Products set price = '300.00' where title = 'React course'; 6 | ``` 7 | | create_date | product_id | title | description | price | 8 | | ------------------------ | ------------------------------------ | -------------------------------------------------- | ------------------------------------------- | ------- | 9 | | 2019-04-11T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | React course | This course you will learn all about React. | $300.00 | 10 | 11 | --- 12 | 13 | ## 2. 14 | ```sql 15 | update Products set price = '300.00', description = 'The new updated SQL course desctiption' where title = 'SQL course'; 16 | ``` 17 | | create_date | product_id | title | description | price | 18 | | ------------------------ | ------------------------------------ | -------------------------------------------------- | -------------------------------------- | ------- | 19 | | 2019-04-11T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | SQL course | The new updated SQL course desctiption | $300.00 | 20 | 21 | --- 22 | -------------------------------------------------------------------------------- /solutions/05-removing-data-with-sql-delete-truncate-and-drop-solutions.md: -------------------------------------------------------------------------------- 1 | # Removing Data with SQL Delete, Truncate, and Drop Solutions 2 | 3 | ## 1. 4 | ```sql 5 | delete from Products where title = 'React course'; 6 | ``` 7 | ## 2. 8 | ```sql 9 | truncate Products; 10 | ``` 11 | ## 3. 12 | ```sql 13 | drop table Products; 14 | ``` -------------------------------------------------------------------------------- /solutions/06-keep-data-integrity-with-constraints-solutions.md: -------------------------------------------------------------------------------- 1 | # Keep Data Integrity with Constraints Solutions 2 | 3 | ## 1. 4 | ```sql 5 | create table Products ( 6 | create_date date not null, 7 | product_id uuid not null primary key, 8 | title character(50) not null, 9 | description text, 10 | price money not null, 11 | technology character(50) not null 12 | ); 13 | ``` -------------------------------------------------------------------------------- /solutions/07-organize-table-data-with-indexes-solutions.md: -------------------------------------------------------------------------------- 1 | ## 1. 2 | ```sql 3 | create index test1_product_id_index on Products (product_id); 4 | ``` 5 | 6 | ## 2. 7 | ```sql 8 | \d Products 9 | ``` 10 | Table "public.products" 11 | | Column | Type | Collation | Nullable | Default | 12 | | ----------------------- | --------------| ----------- | ----------- | ----------- | 13 | | create_date | date | | | | 14 | | product_id | uuid | | | | 15 | | title | character | | | | 16 | | description | text | | | | 17 | | price | money | | | | 18 | | technology | character | | | | 19 | 20 | Indexes: "test1_product_id_index" btree (product_id) 21 | 22 | ## 3. 23 | ```sql 24 | create index test1_product_id_and_technology_index on Products (product_id, technology); 25 | ``` 26 | Table "public.products" 27 | | Column | Type | Collation | Nullable | Default | 28 | | ----------------------- | --------------| ----------- | ----------- | ----------- | 29 | | create_date | date | | | | 30 | | product_id | uuid | | | | 31 | | title | character | | | | 32 | | description | text | | | | 33 | | price | money | | | | 34 | | technology | character | | | | 35 | 36 | Indexes: 37 | "test1_product_id_and_technology_index" btree (product_id, technology) 38 | "test1_product_id_index" btree (product_id) -------------------------------------------------------------------------------- /solutions/08-select-grouped-and-aggregated-data-with-sql-solutions.md: -------------------------------------------------------------------------------- 1 | # Select Grouped and Aggregated Data with SQL Solutions 2 | 3 | ## 1. 4 | select sum(price) from Products; 5 | 6 | | sum | 7 | | --------- | 8 | | $1,650.00 | 9 | 10 | --- 11 | 12 | 13 | 14 | ## 2. 15 | select max(price), technology from Products group by technology; 16 | 17 | | max | technology | 18 | | ------- | -------------------------------------------------- | 19 | | $150.00 | react | 20 | | $450.00 | angular | 21 | | $550.00 | sql | 22 | | $350.00 | vue | 23 | 24 | --- -------------------------------------------------------------------------------- /solutions/09-conditionally-select-out-filtered-data-with-sql-where-solutions.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 1. 4 | ```sql 5 | select * from Products where price < '100.00'; 6 | ``` 7 | | create_date | product_id | title | description | price | 8 | | ------------------------ | ------------------------------------ | -------------------------------------------------- | ------------------------------------------------ | ------ | 9 | | 2019-04-11T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | short React course | This course you will start to learn about React. | $50.00 | 10 | | 2019-04-11T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | short Vue course | This course you will start to learn about Vue. | $50.00 | 11 | | 2019-04-11T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | short Angular course | This course you will start learning Angular. | $50.00 | 12 | --- 13 | ## 2. 14 | ```sql 15 | select * from Products where title = 'SQL course'; 16 | ``` 17 | | create_date | product_id | title | description | price | 18 | | ------------------------ | ------------------------------------ | -------------------------------------------------- | ----------------------------------------- | ------- | 19 | | 2019-04-11T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | SQL course | This course you will learn all about SQL. | $550.00 | 20 | 21 | --- 22 | ## Extra Credit 23 | ```sql 24 | select * from Products where title LIKE '%React%'; 25 | ``` 26 | | create_date | product_id | title | description | price | 27 | | ------------------------ | ------------------------------------ | -------------------------------------------------- | ------------------------------------------------ | ------- | 28 | | 2019-04-11T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | short React course | This course you will start to learn about React. | $50.00 | 29 | | 2019-04-11T00:00:00.000Z | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | React course | This course you will learn all about React. | $150.00 | 30 | 31 | --- -------------------------------------------------------------------------------- /solutions/10-combining-tables-together-with-sql-join-statements-solutions.md: -------------------------------------------------------------------------------- 1 | ## 1. 2 | ```sql 3 | select p.title as Product, pp.date as DatePurchased from Products p left outer join Purchases pp on p.product_id = pp.sku; 4 | ``` 5 | | product | datepurchased | 6 | | -------------------------------------------------- | ------------------------ | 7 | | SQL course | 2019-04-22T00:00:00.000Z | 8 | | Angular course | 2019-11-23T00:00:00.000Z | 9 | | short Vue course | 2019-07-02T00:00:00.000Z | 10 | | short React course | 2019-09-02T00:00:00.000Z | 11 | | SQL course | 2019-05-23T00:00:00.000Z | 12 | | Angular course | 2019-11-02T00:00:00.000Z | 13 | | Angular course | 2019-04-02T00:00:00.000Z | 14 | | SQL course | 2019-11-02T00:00:00.000Z | 15 | | Vue course | 2019-02-02T00:00:00.000Z | 16 | | React course | 2019-04-23T00:00:00.000Z | 17 | | short Angular course | 2019-04-02T00:00:00.000Z | 18 | | Vue course | 2019-11-02T00:00:00.000Z | 19 | | React course | 2019-10-23T00:00:00.000Z | 20 | | short Vue course | 2019-04-12T00:00:00.000Z | 21 | | React course | 2019-02-15T00:00:00.000Z | 22 | 23 | --- 24 | 25 | ## 2. 26 | ```sql 27 | select p.title as Product, pp.date as DatePurchased, pp.quantity from Products p left outer join Purchases pp on p.product_id = pp.sku where pp.date < '2019-06-15'; 28 | ``` 29 | | product | date | quantity | 30 | | -------------------------------------------------- | ------------------------ | ------------ | 31 | | SQL course | 2019-04-22T00:00:00.000Z | 1 | 32 | | SQL course | 2019-05-23T00:00:00.000Z | 6 | 33 | | Angular course | 2019-04-02T00:00:00.000Z | 2 | 34 | | Vue course | 2019-02-02T00:00:00.000Z | 1 | 35 | | React course | 2019-04-23T00:00:00.000Z | 1 | 36 | | short Angular course | 2019-04-02T00:00:00.000Z | 4 | 37 | | short Vue course | 2019-04-12T00:00:00.000Z | 1 | 38 | | React course | 2019-02-15T00:00:00.000Z | 2 | 39 | 40 | --- -------------------------------------------------------------------------------- /solutions/11-subquery-dynamic-datasets-in-sql-solutions.md: -------------------------------------------------------------------------------- 1 | ## 1. 2 | ```sql 3 | select user_handle, sku, (select avg(quantity) from Purchases where user_handle = p.user_handle and sku = p.sku) from Purchases p group by user_handle, sku; 4 | ``` 5 | | user_handle | sku | avg | 6 | | ------------------------------------ | ------------------------------------ | ---------------------- | 7 | | 3bd67317-0efa-48c9-914c-42234072d94b | 75f9eaba-136e-4b79-9579-5fd47b48797f | 7.0000000000000000 | 8 | | 4ff119f0-91b1-4020-8005-69bf0dd8b492 | 40c88e1e-0910-4017-9b6f-12337e22183a | 2.5000000000000000 | 9 | | 4ff119f0-91b1-4020-8005-69bf0dd8b492 | 75f9eaba-136e-4b79-9579-5fd47b48797f | 1.00000000000000000000 | 10 | | 3bd67317-0efa-48c9-914c-42234072d94b | 5a2a8657-60d6-4d67-ac34-28f9a47a71d3 | 2.0000000000000000 | 11 | | 4ff119f0-91b1-4020-8005-69bf0dd8b492 | 5a2a8657-60d6-4d67-ac34-28f9a47a71d3 | 1.00000000000000000000 | 12 | | 4ff119f0-91b1-4020-8005-69bf0dd8b492 | a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 | 2.0000000000000000 | 13 | | 3bd67317-0efa-48c9-914c-42234072d94b | 13e55094-00d5-4c9b-bd8e-ce38072ae551 | 1.00000000000000000000 | 14 | | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 75f9eaba-136e-4b79-9579-5fd47b48797f | 6.0000000000000000 | 15 | | 4ff119f0-91b1-4020-8005-69bf0dd8b492 | 13e55094-00d5-4c9b-bd8e-ce38072ae551 | 1.00000000000000000000 | 16 | | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 40c88e1e-0910-4017-9b6f-12337e22183a | 4.0000000000000000 | 17 | | 4ff119f0-91b1-4020-8005-69bf0dd8b492 | 562951b6-3648-42fd-b49e-156c6a7edf60 | 1.00000000000000000000 | 18 | | 3bd67317-0efa-48c9-914c-42234072d94b | 562951b6-3648-42fd-b49e-156c6a7edf60 | 1.00000000000000000000 | 19 | | 3bd67317-0efa-48c9-914c-42234072d94b | 18c299a8-772a-424b-841e-f3d082019271 | 4.0000000000000000 | 20 | | 6ab3b2d2-8e02-890c-bb6d-61a67cd43f31 | 5a2a8657-60d6-4d67-ac34-28f9a47a71d3 | 3.0000000000000000 | 21 | 22 | --- 23 | ## 2. 24 | ```sql 25 | select total, title from Products pr inner join (select count(sku) as total, sku from Purchases group by sku) p on p.sku = pr.product_id; 26 | ``` 27 | | total | title | 28 | | ----- | -------------------------------------------------- | 29 | | 1 | short React course | 30 | | 3 | React course | 31 | | 2 | short Vue course | 32 | | 2 | Vue course | 33 | | 1 | short Angular course | 34 | | 3 | Angular course | 35 | | 3 | SQL course | 36 | 37 | --- --------------------------------------------------------------------------------