├── README.md └── course ├── 1-what_is_sql └── exercises │ ├── 1-what-is-sql │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 2-select-statement │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 3-sql-technologies │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 4-nosql-vs-sql │ ├── multiple_choice.json │ └── readme.md │ ├── 4a-nosql-vs-sql │ ├── multiple_choice.json │ └── readme.md │ ├── 4b-nosql-vs-sql │ ├── multiple_choice.json │ └── readme.md │ └── 5-sql-tech-compare │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql ├── 10-joining-tables └── exercises │ ├── 1-inner_join │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 2-namespacing │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 3-left_join │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 4-right_join │ ├── multiple_choice.json │ └── readme.md │ ├── 5-full_join │ ├── multiple_choice.json │ └── readme.md │ ├── 6-joins_quiz │ ├── multiple_choice.json │ └── readme.md │ ├── 7-join_quiz │ ├── multiple_choice.json │ └── readme.md │ ├── 8-join_quiz │ ├── multiple_choice.json │ └── readme.md │ └── 9-join_practice │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql ├── 11-database_performance └── exercises │ ├── 1-indexes │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 2-index_review │ ├── multiple_choice.json │ └── readme.md │ ├── 2a-index_review │ ├── multiple_choice.json │ └── readme.md │ ├── 2b-index_review │ ├── multiple_choice.json │ └── readme.md │ ├── 3-multi_column_idx │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 4-denormalizing │ ├── multiple_choice.json │ └── readme.md │ ├── 4a-denormalizing │ ├── multiple_choice.json │ └── readme.md │ ├── 4b-denormalizing │ ├── multiple_choice.json │ └── readme.md │ ├── 5-sql-injection │ ├── multiple_choice.json │ └── readme.md │ └── 5a-sql-injection │ ├── multiple_choice.json │ └── readme.md ├── 2-tables └── exercises │ ├── 1-create_table │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 1a-create_table │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 2-alter_table │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 3-intro_to_migrations │ ├── multiple_choice.json │ └── readme.md │ ├── 3a-intro_to_migrations │ ├── multiple_choice.json │ └── readme.md │ ├── 3b-intro_to_migrations │ ├── multiple_choice.json │ └── readme.md │ ├── 4-migration_practice │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 5-datatypes │ ├── multiple_choice.json │ └── readme.md │ ├── 5a-datatypes │ ├── multiple_choice.json │ └── readme.md │ └── 5b-datatypes │ ├── multiple_choice.json │ └── readme.md ├── 3-constraints └── exercises │ ├── 1-null_values │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 2-constraints │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 3-primary_keys │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 4-foreign_keys │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 5-intro_to_schema │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 6-relational_databases │ ├── multiple_choice.json │ └── readme.md │ ├── 6a-relational_databases │ ├── multiple_choice.json │ └── readme.md │ ├── 7-relational_nonrelational │ ├── multiple_choice.json │ └── readme.md │ └── 7a-relational_nonrelational │ ├── multiple_choice.json │ └── readme.md ├── 4-crud └── exercises │ ├── 1-what_is_crud │ ├── code.sql │ ├── complete.sql │ ├── hint.md │ ├── readme.md │ └── up.sql │ ├── 10-delete_danger │ ├── multiple_choice.json │ └── readme.md │ ├── 10a-delete_danger │ ├── multiple_choice.json │ └── readme.md │ ├── 11-update │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 12-orm │ ├── multiple_choice.json │ └── readme.md │ ├── 12a-orm │ ├── multiple_choice.json │ └── readme.md │ ├── 12b-orm │ ├── multiple_choice.json │ └── readme.md │ ├── 2-create │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 2-http_create │ ├── multiple_choice.json │ └── readme.md │ ├── 2a-http_create │ ├── multiple_choice.json │ └── readme.md │ ├── 3-autoincrement │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 4-manual_entry │ ├── multiple_choice.json │ └── readme.md │ ├── 4a-manual_entry │ ├── multiple_choice.json │ └── readme.md │ ├── 5-count │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 6-http_read │ ├── multiple_choice.json │ └── readme.md │ ├── 6a-http_read │ ├── multiple_choice.json │ └── readme.md │ ├── 7-where_clause │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 8-where_null │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ └── 9-delete │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql ├── 5-basic_queries └── exercises │ ├── 1-as_clause │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 2-functions │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 3-between │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 3-distinct │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 4-and │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 5-or │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 6-in │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 7-like_percent │ ├── code.sql │ ├── complete.sql │ ├── hint.md │ ├── readme.md │ └── up.sql │ ├── 8-like_underscore │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 9-like_quiz │ ├── multiple_choice.json │ └── readme.md │ └── 9a-like_quiz │ ├── multiple_choice.json │ └── readme.md ├── 6-structuring_return_data └── exercises │ ├── 1-limit │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 2-limit_quiz │ ├── multiple_choice.json │ └── readme.md │ ├── 2a-limit_quiz │ ├── multiple_choice.json │ └── readme.md │ ├── 3-order_by │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 4-order_by_quiz │ ├── multiple_choice.json │ └── readme.md │ ├── 4a-order_by_quiz │ ├── multiple_choice.json │ └── readme.md │ └── 5-order_limit │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql ├── 7-aggregations └── exercises │ ├── 1-count │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 2-sum │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 3-max │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 4-min │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 5-group_by │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 6-average │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 7-having │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 8-having_vs_where │ ├── multiple_choice.json │ └── readme.md │ ├── 8a-having_vs_where │ ├── multiple_choice.json │ └── readme.md │ └── 9-round │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql ├── 8-subqueries └── exercises │ ├── 1-subqueries │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ ├── 2-subqueries_quiz │ ├── multiple_choice.json │ └── readme.md │ ├── 2a-subqueries_quiz │ ├── multiple_choice.json │ └── readme.md │ ├── 3-no_tables │ ├── code.sql │ ├── complete.sql │ ├── readme.md │ └── up.sql │ └── 4-no_tables_quiz │ ├── multiple_choice.json │ └── readme.md └── 9-normalization └── exercises ├── 1-one_to_one ├── multiple_choice.json └── readme.md ├── 10-normalization_review ├── multiple_choice.json └── readme.md ├── 10a-normalization_review ├── multiple_choice.json └── readme.md ├── 10b-normalization_review ├── multiple_choice.json └── readme.md ├── 1a-one_to_one ├── multiple_choice.json └── readme.md ├── 2-one_to_many ├── code.sql ├── complete.sql ├── readme.md └── up.sql ├── 3-many_to_many ├── code.sql ├── complete.sql ├── readme.md └── up.sql ├── 4-normalization ├── multiple_choice.json └── readme.md ├── 4a-normalization ├── multiple_choice.json └── readme.md ├── 5-normal_forms ├── multiple_choice.json └── readme.md ├── 5a-normal_forms ├── multiple_choice.json └── readme.md ├── 5b-normal_forms ├── multiple_choice.json └── readme.md ├── 6-first_nf ├── code.sql ├── complete.sql ├── readme.md └── up.sql ├── 7-second_nf ├── code.sql ├── complete.sql ├── readme.md └── up.sql ├── 8-third_nf ├── code.sql ├── complete.sql ├── readme.md └── up.sql └── 9-boyce_codd_nf ├── multiple_choice.json └── readme.md /README.md: -------------------------------------------------------------------------------- 1 | # fcc-learn-sql-assets 2 | 3 | This is a snapshot of the code samples for the ["Learn SQL" course](https://boot.dev/courses/learn-sql) on [Boot.dev](https://boot.dev) at the time the video for FreeCodeCamp was released on YouTube. If you want the most up-to-date version of the code, please visit the official [Boot.dev course](https://boot.dev/courses/learn-sql). Otherwise, if you're looking for the files used in the video, you're in the right place! 4 | 5 | * [Course code samples](/course) 6 | 7 | ## License 8 | 9 | You are free to use this content and code for personal education purposes. However, you are *not* authorized to publish this content or code elsewhere, whether for commercial purposes or not. 10 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/1-what-is-sql/code.sql: -------------------------------------------------------------------------------- 1 | SELECT * from people; 2 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/1-what-is-sql/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * from users; 2 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/1-what-is-sql/readme.md: -------------------------------------------------------------------------------- 1 | # What is SQL? 2 | 3 | Structured Query Language, or [SQL](https://en.wikipedia.org/wiki/SQL), is the primary programming language used to manage and interact with [relational databases](https://cloud.google.com/learn/what-is-a-relational-database). SQL can perform various operations such as creating, updating, reading, and deleting records within a database. 4 | 5 | @[youtube](https://www.youtube.com/watch?v=pYKirBUnr-8) 6 | 7 | ## CashPal 8 | 9 | In this course, we will be building the database for a pretend PayPal clone called *CashPal*! Storing information related to people's money, transactions, and identity is very important! So we will need to make sure we use proper conventions to build a safe, and reliable database architecture that our users can rely on. 10 | 11 | ## Assignment 12 | 13 | I have provided a simple SQL statement for you that retrieves some records from a table. However there isn't a `people` table, the table in our database is called `users`. Fix the bug by changing `people` to `users` within the `SELECT` statement. 14 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/1-what-is-sql/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users (id INTEGER, name TEXT, age INTEGER, is_admin BOOLEAN); 2 | INSERT into users (id, name, age, is_admin) values (1, 'John Doe', 27, false); 3 | INSERT into users (id, name, age, is_admin) values (2, 'Sally Rae', 18, true); 4 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/2-select-statement/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/1-what_is_sql/exercises/2-select-statement/code.sql -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/2-select-statement/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT name, balance from users; 2 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/2-select-statement/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users (id INTEGER, name TEXT, age INTEGER, balance INTEGER, is_admin BOOLEAN); 2 | INSERT into users (id, name, age, balance, is_admin) values (1, 'John Smith', 28, 450.00, true); 3 | INSERT into users (id, name, age, balance, is_admin) values (2, 'Darren Walker', 27, 200.00, true); 4 | INSERT into users (id, name, age, balance, is_admin) values (2, 'Jane Morris', 33, 496.24, false); 5 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/3-sql-technologies/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/1-what_is_sql/exercises/3-sql-technologies/code.sql -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/3-sql-technologies/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT id, name, is_admin from users; 2 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/3-sql-technologies/readme.md: -------------------------------------------------------------------------------- 1 | # Which Databases Use SQL? 2 | 3 | SQL is just a query language. You typically use it to interact with a specific database technology. For example: 4 | 5 | * [SQLite](https://www.sqlite.org/index.html) 6 | * [PostgreSQL](https://www.postgresql.org/) 7 | * [MySQL](https://www.mysql.com/) 8 | * [CockroachDB](https://www.cockroachlabs.com/) 9 | * [Oracle](https://www.oracle.com/database/) 10 | * etc... 11 | 12 | Although many different databases use the SQL *language*, most of them will have their own *dialect*. It's *critical* to understand that *not* all databases are created equal. Just because one SQL-compatible database does things a certain way, doesn't mean every SQL-compatible database will follow those exact same patterns. 13 | 14 | ## We're using SQLite 15 | 16 | In this course, we'll be using [SQLite](https://www.sqlite.org/index.html) specifically. SQLite is great for embedded projects, web browsers, and toy projects. It's lightweight, but has limited functionality compared to the likes of PostgreSQL or MySQL - two of the more common production SQL technologies. 17 | 18 | We'll point out to you whenever some functionality we're working with is unique to SQLite! 19 | 20 | ## Assignment 21 | 22 | One way in which SQLite is a bit different is that it stores Boolean values as integers - the integers `0` and `1`. 23 | 24 | * `0` = `false` 25 | * `1` = `true` 26 | 27 | Select all of the `id`s, `name`s, and `is_admin` flags from the `users` table. 28 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/3-sql-technologies/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users (id INTEGER, name TEXT, age INTEGER, is_admin BOOLEAN); 2 | INSERT into users (id, name, age, is_admin) values (1, 'Lane Holland', 27, false); 3 | INSERT into users (id, name, age, is_admin) values (2, 'Allan Rae', 18, true); 4 | INSERT into users (id, name, age, is_admin) values (2, 'Sally Wagoner', 18, true); 5 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/4-nosql-vs-sql/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Each NoSQL Database tends to use ____ query language(s)", 3 | "answers": [ 4 | "different", 5 | "the same" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/4-nosql-vs-sql/readme.md: -------------------------------------------------------------------------------- 1 | # NoSQL vs SQL 2 | 3 | When talking about SQL databases, we also have to mention the elephant in the room: [NoSQL](https://en.wikipedia.org/wiki/NoSQL). 4 | 5 | To put it simply, a NoSQL database is a database that does *not* use SQL (Structured Query Language). Each NoSQL typically has its own way of writing and executing queries. For example, [MongoDB](https://www.mongodb.com/) uses MQL (MongoDB Query Language) and [ElasticSearch](https://www.elastic.co/) simply has a JSON API. 6 | 7 | While most relational databases are fairly similar, NoSQL databases tend to be fairly unique and are used for more niche purposes. Some of the main differences between a SQL and NoSQL databases are: 8 | 9 | 1. NoSQL databases are usually non-relational, SQL databases are usually [relational](https://cloud.google.com/learn/what-is-a-relational-database) (we'll talk more about what this means later). 10 | 2. SQL databases usually have a defined schema, NoSQL databases usually have dynamic schema. 11 | 3. SQL databases are table-based, NoSQL databases have a variety of different storage methods, such as document, key-value, graph, wide-column, and more. 12 | 13 | @[youtube](https://www.youtube.com/watch?v=NovjCrDFlXk) 14 | 15 | ## Types of NoSQL databases 16 | 17 | * [Document Database](https://en.wikipedia.org/wiki/Document-oriented_database) 18 | * [Key-Value Store](https://en.wikipedia.org/wiki/Key%E2%80%93value_database) 19 | * [Wide-Column](https://en.wikipedia.org/wiki/Wide-column_store) 20 | * [Graph](https://en.wikipedia.org/wiki/Graph_database) 21 | 22 | A few of the most popular NoSQL databases are: 23 | 24 | * [MongoDB](https://en.wikipedia.org/wiki/MongoDB) 25 | * [Cassandra](https://en.wikipedia.org/wiki/Apache_Cassandra) 26 | * [CouchDB](https://en.wikipedia.org/wiki/Apache_CouchDB) 27 | * [DynamoDB](https://en.wikipedia.org/wiki/Amazon_DynamoDB) 28 | * [ElasticSearch](https://www.elastic.co/) 29 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/4a-nosql-vs-sql/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "____ compatible databases tend to be more similar in their functionality than ____ databases", 3 | "answers": [ 4 | "SQL, NoSQL", 5 | "NoSQL, SQL" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/4a-nosql-vs-sql/readme.md: -------------------------------------------------------------------------------- 1 | # NoSQL vs SQL 2 | 3 | When talking about SQL databases, we also have to mention the elephant in the room: [NoSQL](https://en.wikipedia.org/wiki/NoSQL). 4 | 5 | To put it simply, a NoSQL database is a database that does *not* use SQL (Structured Query Language). Each NoSQL typically has its own way of writing and executing queries. For example, [MongoDB](https://www.mongodb.com/) uses MQL (MongoDB Query Language) and [ElasticSearch](https://www.elastic.co/) simply has a JSON API. 6 | 7 | While most relational databases are fairly similar, NoSQL databases tend to be fairly unique and are used for more niche purposes. Some of the main differences between a SQL and NoSQL databases are: 8 | 9 | 1. NoSQL databases are usually non-relational, SQL databases are usually [relational](https://cloud.google.com/learn/what-is-a-relational-database) (we'll talk more about what this means later). 10 | 2. SQL databases usually have a defined schema, NoSQL databases usually have dynamic schema. 11 | 3. SQL databases are table-based, NoSQL databases have a variety of different storage methods, such as document, key-value, graph, wide-column, and more. 12 | 13 | @[youtube](https://www.youtube.com/watch?v=NovjCrDFlXk) 14 | 15 | ## Types of NoSQL databases 16 | 17 | * [Document Database](https://en.wikipedia.org/wiki/Document-oriented_database) 18 | * [Key-Value Store](https://en.wikipedia.org/wiki/Key%E2%80%93value_database) 19 | * [Wide-Column](https://en.wikipedia.org/wiki/Wide-column_store) 20 | * [Graph](https://en.wikipedia.org/wiki/Graph_database) 21 | 22 | A few of the most popular NoSQL databases are: 23 | 24 | * [MongoDB](https://en.wikipedia.org/wiki/MongoDB) 25 | * [Cassandra](https://en.wikipedia.org/wiki/Apache_Cassandra) 26 | * [CouchDB](https://en.wikipedia.org/wiki/Apache_CouchDB) 27 | * [DynamoDB](https://en.wikipedia.org/wiki/Amazon_DynamoDB) 28 | * [ElasticSearch](https://www.elastic.co/) 29 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/4b-nosql-vs-sql/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which type of database always uses table structures?", 3 | "answers": [ 4 | "SQL", 5 | "NoSQL", 6 | "Both" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/4b-nosql-vs-sql/readme.md: -------------------------------------------------------------------------------- 1 | # NoSQL vs SQL 2 | 3 | When talking about SQL databases, we also have to mention the elephant in the room: [NoSQL](https://en.wikipedia.org/wiki/NoSQL). 4 | 5 | To put it simply, a NoSQL database is a database that does *not* use SQL (Structured Query Language). Each NoSQL typically has its own way of writing and executing queries. For example, [MongoDB](https://www.mongodb.com/) uses MQL (MongoDB Query Language) and [ElasticSearch](https://www.elastic.co/) simply has a JSON API. 6 | 7 | While most relational databases are fairly similar, NoSQL databases tend to be fairly unique and are used for more niche purposes. Some of the main differences between a SQL and NoSQL databases are: 8 | 9 | 1. NoSQL databases are usually non-relational, SQL databases are usually [relational](https://cloud.google.com/learn/what-is-a-relational-database) (we'll talk more about what this means later). 10 | 2. SQL databases usually have a defined schema, NoSQL databases usually have dynamic schema. 11 | 3. SQL databases are table-based, NoSQL databases have a variety of different storage methods, such as document, key-value, graph, wide-column, and more. 12 | 13 | @[youtube](https://www.youtube.com/watch?v=NovjCrDFlXk) 14 | 15 | ## Types of NoSQL databases 16 | 17 | * [Document Database](https://en.wikipedia.org/wiki/Document-oriented_database) 18 | * [Key-Value Store](https://en.wikipedia.org/wiki/Key%E2%80%93value_database) 19 | * [Wide-Column](https://en.wikipedia.org/wiki/Wide-column_store) 20 | * [Graph](https://en.wikipedia.org/wiki/Graph_database) 21 | 22 | A few of the most popular NoSQL databases are: 23 | 24 | * [MongoDB](https://en.wikipedia.org/wiki/MongoDB) 25 | * [Cassandra](https://en.wikipedia.org/wiki/Apache_Cassandra) 26 | * [CouchDB](https://en.wikipedia.org/wiki/Apache_CouchDB) 27 | * [DynamoDB](https://en.wikipedia.org/wiki/Amazon_DynamoDB) 28 | * [ElasticSearch](https://www.elastic.co/) 29 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/5-sql-tech-compare/code.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users (id INTEGER, name TEXT, age INTEGER); 2 | INSERT into users (id, name, age) values (1, 'John Doe', 21); 3 | INSERT into users (id, name, age) values (2, 'Montgomery Burns', 33); 4 | SELECT * from users; 5 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/5-sql-tech-compare/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users (id INTEGER, name TEXT, age INTEGER); 2 | INSERT into users (id, name, age) values (1, 'John Doe', 21); 3 | INSERT into users (id, name, age) values (2, 1, 33); 4 | SELECT * from users; 5 | -------------------------------------------------------------------------------- /course/1-what_is_sql/exercises/5-sql-tech-compare/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/1-what_is_sql/exercises/5-sql-tech-compare/up.sql -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/1-inner_join/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/10-joining-tables/exercises/1-inner_join/code.sql -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/1-inner_join/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM users 3 | INNER JOIN countries 4 | ON countries.country_code = users.country_code; -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/1-inner_join/readme.md: -------------------------------------------------------------------------------- 1 | # Joins 2 | 3 | Joins are one of the most important features that SQL offers. Joins allow us to make use of the relationships we have set up between our tables. In short, joins allow us to query multiple tables at the *same time.* 4 | 5 | ## Inner Join 6 | 7 | The simplest and most common type of join in SQL is the `INNER JOIN`. By default, a `JOIN` command is an `INNER JOIN`. An `INNER JOIN` returns all of the records in `table_a` that have matching records in `table_b` as demonstrated by the following Venn diagram. 8 | 9 | ![inner join](https://i.imgur.com/wgxAmhA.png) 10 | 11 | ## On 12 | 13 | In order to perform a join, we need to tell the database which fields should be "matched up". The `ON` clause is used to specify these columns to join. 14 | 15 | ```SQL 16 | SELECT * 17 | FROM employees 18 | INNER JOIN departments 19 | ON employees.department_id = departments.id; 20 | ``` 21 | 22 | The query above returns *all* the fields from *both* tables. The `INNER` keyword doesn't have anything to do with the number of *columns* returned - it only affects the number of *rows* returned. 23 | 24 | ## Assignment 25 | 26 | Our frontend team is working on a profile page and would like to display a user's country *name* instead of just the country's two-letter *code*. Let's start by writing a simple join between the `users` table and `countries` table. We will expand on this query more in the next exercise. 27 | 28 | * Write an `INNER JOIN` between `users` and `countries` 29 | * Return *all* fields from both tables 30 | * Join on the `country_code` field 31 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/2-namespacing/code.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM users 3 | INNER JOIN countries on countries.country_code = users.country_code; -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/2-namespacing/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT users.name, users.age, countries.name as country_name 2 | FROM users 3 | INNER JOIN countries on countries.country_code = users.country_code 4 | ORDER BY country_name; 5 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/2-namespacing/readme.md: -------------------------------------------------------------------------------- 1 | # Namespacing on Tables 2 | 3 | When working with multiple tables, you can specify which table a field exists on using a `.`. For example: 4 | 5 | > table_name.column_name 6 | 7 | ```SQL 8 | SELECT students.name, classes.name 9 | FROM students 10 | INNER JOIN classes on classes.class_id = students.class_id; 11 | ``` 12 | 13 | The above query returns the `name` field from the `students` table and the `name` field from the `classes` table. 14 | 15 | ## Assignment 16 | 17 | Adjust the query to: 18 | 19 | * Return the `name`, and `age` fields from the `users` table. 20 | * Return the `name` field from the `countries` table and rename it to `country_name`. 21 | * Sort by the `country_name` in ascending order. 22 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/3-left_join/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/10-joining-tables/exercises/3-left_join/code.sql -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/3-left_join/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT users.name, sum(transactions.amount) as sum, count(transactions.id) as count 2 | FROM users 3 | LEFT JOIN transactions 4 | ON users.id = transactions.user_id 5 | GROUP BY users.id 6 | ORDER BY sum DESC; 7 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/3-left_join/readme.md: -------------------------------------------------------------------------------- 1 | # Left Join 2 | 3 | A `LEFT JOIN` will return every record from `table_a` regardless of whether or not any of those records have a match in `table_b`. A left join will *also* return any matching records from `table_b`. Here is a Venn diagram to help visualize the effect of a `LEFT JOIN`. 4 | 5 | ![left-join](https://i.imgur.com/mNbhWfM.png) 6 | 7 | A small trick you can do to make writing the SQL query easier is define an [alias](https://en.wikipedia.org/wiki/Alias_(SQL)) for each table. Here's an example: 8 | 9 | ```SQL 10 | SELECT e.name, d.name 11 | FROM employees e 12 | LEFT JOIN departments d 13 | ON e.department_id = d.id; 14 | ``` 15 | 16 | Notice the simple alias declarations `e` and `d` for `employees` and `departments` respectively. 17 | 18 | Some developers do this to make their queries less verbose. That said, I personally *hate it* because single-letter variables are harder to understand the meaning of. 19 | 20 | ## Assignment 21 | 22 | The *CashPal* team needs a report on all the transactions a user has made. Join the `users` and `transactions` tables on `users.id` and `transactions.user_id`. 23 | 24 | Your query should return 3 fields: 25 | 26 | 1. A user's `name` as `name` 27 | 2. The sum of all of their transaction `amount`s as `sum` 28 | 3. The count of all of their transactions as `count` 29 | 30 | * Be sure to order the data by the `sum` field in descending order. 31 | * Be sure to still return user records of users who have no transactions. 32 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/4-right_join/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "We can retrieve the same records with a RIGHT JOIN and a LEFT JOIN by...", 3 | "answers": [ 4 | "flipping the position of the tables in the join statement", 5 | "giving up and drawing Venn diagrams", 6 | "changing the field the tables are joined on", 7 | "grouping the table by a different field" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/4-right_join/readme.md: -------------------------------------------------------------------------------- 1 | # Right Join 2 | 3 | A `RIGHT JOIN` is, as you may expect, the opposite of a `LEFT JOIN`. It returns all records from `table_b` regardless of matches, and all matching records between the two tables. 4 | 5 | ![right-join](https://i.imgur.com/LG6Y43j.png) 6 | 7 | ## SQLite Restriction 8 | 9 | SQLite does *not* support right joins, but many dialects of SQL do! If you think about it, a `RIGHT JOIN` is just a `LEFT JOIN` with the order of the tables switched, so it's not a big deal that SQLite doesn't support the syntax. 10 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/5-full_join/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Select the best scenario to use a FULL JOIN?", 3 | "answers": [ 4 | "When you need every single row from two tables, whether or not they're related", 5 | "When you need all the results from a single table", 6 | "When you need the matching results from two tables", 7 | "when you need all results from one table, and matching results from another" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/5-full_join/readme.md: -------------------------------------------------------------------------------- 1 | # Full Join 2 | 3 | A `FULL JOIN` combines the result set of the `LEFT JOIN` and `RIGHT JOIN` commands. It returns *all* records from both from `table_a` and `table_b` regardless of whether or not they have matches. 4 | 5 | ![Full-join](https://i.imgur.com/Kk3k1Ub.png) 6 | 7 | ## SQLite 8 | 9 | Like `RIGHT JOIN`s, SQLite doesn't support `FULL JOIN`s but they are still important to know! 10 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/6-joins_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Given the tables and query, which JOIN type would produce the result", 3 | "answers": [ 4 | "INNER JOIN", 5 | "LEFT JOIN", 6 | "FULL JOIN" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/7-join_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Given the tables and query, which JOIN type would produce the result", 3 | "answers": [ 4 | "LEFT JOIN", 5 | "INNER JOIN", 6 | "FULL JOIN" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/8-join_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Given the tables and query, which JOIN type would produce the result", 3 | "answers": [ 4 | "RIGHT JOIN", 5 | "INNER JOIN", 6 | "FULL JOIN" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/9-join_practice/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/10-joining-tables/exercises/9-join_practice/code.sql -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/9-join_practice/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT users.id, users.name, users.age, users.username, countries.name as country_name, sum(transactions.amount) as balance 2 | FROM users 3 | INNER JOIN countries 4 | ON users.country_code = countries.country_code 5 | INNER JOIN transactions 6 | ON users.id = transactions.user_id 7 | WHERE users.id = 6; 8 | -------------------------------------------------------------------------------- /course/10-joining-tables/exercises/9-join_practice/readme.md: -------------------------------------------------------------------------------- 1 | # Join Practice 2 | 3 | Joins take some time to get used to, but the key to understanding them and using them effectively is *practice*! 4 | 5 | ## Multiple Joins 6 | 7 | To incorporate data from more than *two* tables, you can utilize multiple joins to execute more complex queries! 8 | 9 | ```SQL 10 | SELECT * 11 | FROM employees 12 | LEFT JOIN departments 13 | ON employees.department_id = departments.id 14 | INNER JOIN regions 15 | ON departments.region_id = regions.id 16 | ``` 17 | 18 | ## Assignment 19 | 20 | Our front-end team is finalizing the *profile* page for *CashPal*. We need to write a query that returns all the `user` data they need for an individual user's profile. The query needs to return the following fields: 21 | 22 | 1. The user's `id` 23 | 2. The user's `name` 24 | 3. The user's `age` 25 | 4. The user's `username` 26 | 5. The user's country name, renamed to `country_name` 27 | 6. The sum of the user's transaction amounts, renamed to `balance` 28 | 29 | Return only a single user record - specifically the one with `id=6` 30 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/1-indexes/code.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | email TEXT, 4 | name TEXT, 5 | age INTEGER 6 | ); 7 | 8 | -- ? -- 9 | 10 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 11 | 12 | SELECT name 13 | FROM sqlite_master 14 | WHERE type = 'index'; 15 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/1-indexes/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | email TEXT, 4 | name TEXT, 5 | age INTEGER 6 | ); 7 | 8 | CREATE INDEX email_idx on users (email); 9 | 10 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 11 | 12 | SELECT name 13 | FROM sqlite_master 14 | WHERE type = 'index'; 15 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/1-indexes/readme.md: -------------------------------------------------------------------------------- 1 | # SQL Indexes 2 | 3 | An index is an in-memory structure that ensures that queries we run on a database are *performant*, that is to say, they run *quickly*. If you can remember back to the data structures course, most database indexes are just [binary trees](https://en.wikipedia.org/wiki/Binary_tree)! The binary tree is stored in [ram](https://en.wikipedia.org/wiki/Random-access_memory) instead of on [disk](https://en.wikipedia.org/wiki/Computer_data_storage), and it makes it easy to lookup the location of an entire row. 4 | 5 | `PRIMARY KEY` columns are indexed by default, ensuring you can look up a row by its `id` very quickly. However, if you have other columns that you want to be able to do quick lookups on, you'll need to *index* them. 6 | 7 | ## CREATE INDEX 8 | 9 | ```sql 10 | CREATE INDEX index_name on table_name (column_name); 11 | ``` 12 | 13 | It's fairly common to name an index after the column it's created on with a suffix of `_idx`. 14 | 15 | ## Assignment 16 | 17 | As it turns out, the front-end frequently finds itself in a state where it knows a user's `email` but not their `id`. Let's add an index to the `email` field called `email_idx`. 18 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/1-indexes/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/11-database_performance/exercises/1-indexes/up.sql -------------------------------------------------------------------------------- /course/11-database_performance/exercises/2-index_review/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "A binary-tree index makes lookups...", 3 | "answers": [ 4 | "O(log(n))", 5 | "O(n)", 6 | "O(n^2)", 7 | "O(n*log(n)" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/2-index_review/readme.md: -------------------------------------------------------------------------------- 1 | # Index Review 2 | 3 | As we discussed, an index is a data structure that can perform quick lookups. By indexing a column, we create a new in-memory structure, usually a binary-tree, where the values in the indexed column are sorted into the tree to keep lookups fast. In terms of Big-O complexity, a binary tree index ensures that lookups are [O(log(n))](https://en.wikipedia.org/wiki/Big_O_notation). 4 | 5 | ## Shouldn't we index everything? We can make the database ultra-fast! 6 | 7 | While indexes make specific kinds of lookups much faster, they also add performance overhead - they can slow down a database in other ways. Think about it, if you index every column, you could have hundreds of binary trees in memory! That needlessly bloats the memory usage of your database. It also means that each time you *insert* a record, that record needs to be added to *many* trees - slowing down your insert speed. 8 | 9 | The rule of thumb is simple: 10 | 11 | > Add an index to columns you know you'll be doing frequent lookups on. Leave everything else un-indexed. You can always add indexes later. 12 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/2a-index_review/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Add indexes to...", 3 | "answers": [ 4 | "Columns that you frequently perform lookups on", 5 | "All columns", 6 | "Only primary keys", 7 | "Only foreign keys" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/2a-index_review/readme.md: -------------------------------------------------------------------------------- 1 | # Index Review 2 | 3 | As we discussed, an index is a data structure that can perform quick lookups. By indexing a column, we create a new in-memory structure, usually a binary-tree, where the values in the indexed column are sorted into the tree to keep lookups fast. In terms of Big-O complexity, a binary tree index ensures that lookups are [O(log(n))](https://en.wikipedia.org/wiki/Big_O_notation). 4 | 5 | ## Shouldn't we index everything? We can make the database ultra-fast! 6 | 7 | While indexes make specific kinds of lookups much faster, they also add performance overhead - they can slow down a database in other ways. Think about it, if you index every column, you could have hundreds of binary trees in memory! That needlessly bloats the memory usage of your database. It also means that each time you *insert* a record, that record needs to be added to *many* trees - slowing down your insert speed. 8 | 9 | The rule of thumb is simple: 10 | 11 | > Add an index to columns you know you'll be doing frequent lookups on. Leave everything else un-indexed. You can always add indexes later. 12 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/2b-index_review/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Indexes slow down...", 3 | "answers": [ 4 | "Write speed", 5 | "Read speed" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/2b-index_review/readme.md: -------------------------------------------------------------------------------- 1 | # Index Review 2 | 3 | As we discussed, an index is a data structure that can perform quick lookups. By indexing a column, we create a new in-memory structure, usually a binary-tree, where the values in the indexed column are sorted into the tree to keep lookups fast. In terms of Big-O complexity, a binary tree index ensures that lookups are [O(log(n))](https://en.wikipedia.org/wiki/Big_O_notation). 4 | 5 | ## Shouldn't we index everything? We can make the database ultra-fast! 6 | 7 | While indexes make specific kinds of lookups much faster, they also add performance overhead - they can slow down a database in other ways. Think about it, if you index every column, you could have hundreds of binary trees in memory! That needlessly bloats the memory usage of your database. It also means that each time you *insert* a record, that record needs to be added to *many* trees - slowing down your insert speed. 8 | 9 | The rule of thumb is simple: 10 | 11 | > Add an index to columns you know you'll be doing frequent lookups on. Leave everything else un-indexed. You can always add indexes later. 12 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/3-multi_column_idx/code.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE transactions ( 2 | id INTEGER PRIMARY KEY, 3 | user_id INTEGER, 4 | recipient_id INTEGER, 5 | sender_id INTEGER, 6 | amount INTEGER 7 | ); 8 | 9 | -- ? -- 10 | 11 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 12 | 13 | SELECT type, name, tbl_name 14 | FROM sqlite_master 15 | WHERE type = 'index'; 16 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/3-multi_column_idx/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE transactions ( 2 | id INTEGER PRIMARY KEY, 3 | user_id INTEGER, 4 | recipient_id INTEGER, 5 | sender_id INTEGER, 6 | amount INTEGER 7 | ); 8 | 9 | CREATE INDEX user_id_recipient_id_idx on transactions 10 | (user_id, recipient_id); 11 | 12 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 13 | 14 | SELECT type, name, tbl_name 15 | FROM sqlite_master 16 | WHERE type = 'index'; 17 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/3-multi_column_idx/readme.md: -------------------------------------------------------------------------------- 1 | # Multi-column indexes 2 | 3 | Multi-column indexes are useful for the exact reason you might think - they speed up lookups that depend on *multiple* columns. 4 | 5 | ## CREATE INDEX 6 | 7 | ```sql 8 | CREATE INDEX first_name_last_name_age_idx 9 | ON users (first_name, last_name, age); 10 | ``` 11 | 12 | A multi-column index is sorted by the first column first, the second column next, and so forth. A lookup on *only* the first column in a multi-column index gets almost all of the performance improvements that it would get from its own single-column index. However, lookups on only the second or third column will have very degraded performance. 13 | 14 | ## Rule of thumb 15 | 16 | Unless you have specific reasons to do something special, only add multi-column indexes if you're doing frequent lookups on a specific combination of columns. 17 | 18 | ## Assignment 19 | 20 | We frequently need to lookup all the transactions between 2 specific users! There's a page on the website that allows a user to lookup all the payments they've made to a friend by that friend's name. 21 | 22 | Add an index on the `user_id` and `recipient_id` columns called `user_id_recipient_id_idx` to speed up our app! 23 | 24 | Make sure the `user_id` is the first column in the index so that we can also use this index to speed up our queries that only care about the `user_id`. 25 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/3-multi_column_idx/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/11-database_performance/exercises/3-multi_column_idx/up.sql -------------------------------------------------------------------------------- /course/11-database_performance/exercises/4-denormalizing/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Denormalizing a database can be used to ____", 3 | "answers": [ 4 | "Speed up the queries", 5 | "Slow down the queries" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/4-denormalizing/readme.md: -------------------------------------------------------------------------------- 1 | # Denormalizing for speed 2 | 3 | We left you with a cliffhanger in the "normalization" chapter. As it turns out, data integrity and deduplication come at a cost, and that cost is *usually* speed. 4 | 5 | Joining tables together, using subqueries, performing aggregations, and running post-hoc calculations *take time*. At very large scales these advanced techniques can actually become a *huge* performance toll on an application - sometimes grinding the database server to a halt. 6 | 7 | Storing duplicate information can drastically speed up an application that needs to look it up in *different ways*. For example, if you store a user's country information right on their user record, no expensive join is required to load their profile page! 8 | 9 | That said, *denormalize at your own risk*! Denormalizing a database incurs a large risk of inaccurate and buggy data. 10 | 11 | In my opinion, it should be used as a kind of "last resort" in the name of speed. 12 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/4a-denormalizing/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "It's smart to start with a ____ database and ____ it as needed for speed.", 3 | "answers": [ 4 | "Normalized, Denormalize", 5 | "Denormalized, Normalize" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/4a-denormalizing/readme.md: -------------------------------------------------------------------------------- 1 | # Denormalizing for speed 2 | 3 | We left you with a cliffhanger in the "normalization" chapter. As it turns out, data integrity and deduplication come at a cost, and that cost is *usually* speed. 4 | 5 | Joining tables together, using subqueries, performing aggregations, and running post-hoc calculations *take time*. At very large scales these advanced techniques can actually become a *huge* performance toll on an application - sometimes grinding the database server to a halt. 6 | 7 | Storing duplicate information can drastically speed up an application that needs to look it up in *different ways*. For example, if you store a user's country information right on their user record, no expensive join is required to load their profile page! 8 | 9 | That said, *denormalize at your own risk*! Denormalizing a database incurs a large risk of inaccurate and buggy data. 10 | 11 | In my opinion, it should be used as a kind of "last resort" in the name of speed. 12 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/4b-denormalizing/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "A ____ database is easier to keep bug-free", 3 | "answers": [ 4 | "Normalized", 5 | "Denormalized", 6 | "It's the same" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/4b-denormalizing/readme.md: -------------------------------------------------------------------------------- 1 | # Denormalizing for speed 2 | 3 | We left you with a cliffhanger in the "normalization" chapter. As it turns out, data integrity and deduplication come at a cost, and that cost is *usually* speed. 4 | 5 | Joining tables together, using subqueries, performing aggregations, and running post-hoc calculations *take time*. At very large scales these advanced techniques can actually become a *huge* performance toll on an application - sometimes grinding the database server to a halt. 6 | 7 | Storing duplicate information can drastically speed up an application that needs to look it up in *different ways*. For example, if you store a user's country information right on their user record, no expensive join is required to load their profile page! 8 | 9 | That said, *denormalize at your own risk*! Denormalizing a database incurs a large risk of inaccurate and buggy data. 10 | 11 | In my opinion, it should be used as a kind of "last resort" in the name of speed. 12 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/5-sql-injection/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "SQL injection is best avoided by using a modern SQL package that handles the sanitization of user-provided values", 3 | "answers": [ 4 | "True", 5 | "False" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/5-sql-injection/readme.md: -------------------------------------------------------------------------------- 1 | # SQL Injection 2 | 3 | SQL is a *very* common way hackers attempt to cause damage or breach a database. One of my favorite [XKCD](https://xkcd.com/327/) comics of all time demonstrates the problem: 4 | 5 | ![bobby tables](https://bobby-tables.com/img/xkcd.png) 6 | 7 | The joke here is that if someone was using this query: 8 | 9 | ```SQL 10 | INSERT INTO students(name) VALUES (?); 11 | ``` 12 | 13 | And the "name" of a student was `'Robert'); DROP TABLE students;--` then the resulting SQL query would look like this: 14 | 15 | ```sql 16 | INSERT INTO students(name) VALUES ('Robert'); DROP TABLE students;--) 17 | ``` 18 | 19 | As you can see, this is actually 2 queries! The first one inserts "Robert" into the database, and the second one *deletes the students table*! 20 | 21 | ## How do we protect against SQL injection? 22 | 23 | You need to be aware of SQL injection attacks, but to be honest the solution these days is to simply use a modern SQL library that sanitizes SQL inputs. We don't often need to sanitize inputs by hand at the application level anymore. 24 | 25 | For example, the Go standard library's SQL packages automatically protects your inputs against SQL attacks if you [use it properly](https://go.dev/doc/database/sql-injection). In short, don't interpolate user input into raw strings yourself - make sure your database library has a way to sanitize inputs, and pass it those raw values. 26 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/5a-sql-injection/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "What happened in the comic?", 3 | "answers": [ 4 | "Every student's data in that school's database was deleted", 5 | "Robert's data was deleted", 6 | "Every teachers's data in that school's database was deleted", 7 | "Robert's grades were changed to be all A's" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/11-database_performance/exercises/5a-sql-injection/readme.md: -------------------------------------------------------------------------------- 1 | # SQL Injection 2 | 3 | SQL is a *very* common way hackers attempt to cause damage or breach a database. One of my favorite [XKCD](https://xkcd.com/327/) comics of all time demonstrates the problem: 4 | 5 | ![bobby tables](https://bobby-tables.com/img/xkcd.png) 6 | 7 | The joke here is that if someone was using this query: 8 | 9 | ```SQL 10 | INSERT INTO students(name) VALUES (?); 11 | ``` 12 | 13 | And the "name" of a student was `'Robert'); DROP TABLE students;--` then the resulting SQL query would look like this: 14 | 15 | ```sql 16 | INSERT INTO students(name) VALUES ('Robert'); DROP TABLE students;--) 17 | ``` 18 | 19 | As you can see, this is actually 2 queries! The first one inserts "Robert" into the database, and the second one *deletes the students table*! 20 | 21 | ## How do we protect against SQL injection? 22 | 23 | You need to be aware of SQL injection attacks, but to be honest the solution these days is to simply use a modern SQL library that sanitizes SQL inputs. We don't often need to sanitize inputs by hand at the application level anymore. 24 | 25 | For example, the Go standard library's SQL packages automatically protects your inputs against SQL attacks if you [use it properly](https://go.dev/doc/database/sql-injection). In short, don't interpolate user input into raw strings yourself - make sure your database library has a way to sanitize inputs, and pass it those raw values. 26 | -------------------------------------------------------------------------------- /course/2-tables/exercises/1-create_table/code.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 4 | 5 | pragma table_info('people'); 6 | -------------------------------------------------------------------------------- /course/2-tables/exercises/1-create_table/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE people ( 2 | id INTEGER, 3 | handle TEXT, 4 | name TEXT, 5 | age INTEGER, 6 | balance INTEGER, 7 | is_admin BOOLEAN 8 | ); 9 | 10 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 11 | 12 | pragma table_info('people'); 13 | -------------------------------------------------------------------------------- /course/2-tables/exercises/1-create_table/readme.md: -------------------------------------------------------------------------------- 1 | # Creating a Table 2 | 3 | The `CREATE TABLE` statement is used to create a new table in a database. 4 | 5 | ## "CREATE TABLE" statement 6 | 7 | To create a table, use the `CREATE TABLE` statement followed by the name of the table and the fields you want in the table. 8 | 9 | ```SQL 10 | CREATE TABLE employees (id INTEGER, name TEXT, age INTEGER, is_manager BOOLEAN, salary INTEGER); 11 | ``` 12 | 13 | Each field name is followed by its *datatype*. We'll get to data types in a minute. 14 | 15 | It's also acceptable and common to break up the `CREATE TABLE` statement with some whitespace like this: 16 | 17 | ```SQL 18 | CREATE TABLE employees( 19 | id INTEGER, 20 | name TEXT, 21 | age INTEGER, 22 | is_manager BOOLEAN, 23 | salary INTEGER 24 | ); 25 | ``` 26 | 27 | ## Assignment 28 | 29 | Let's begin building a table for *CashPal* database! Create the `people` table with the following fields: 30 | 31 | 1. id - `Integer` 32 | 2. handle - `Text` 33 | 3. name - `Text` 34 | 4. age - `Integer` 35 | 5. balance - `Integer` 36 | 6. is_admin - `boolean` 37 | 38 | ## Tip 39 | 40 | The `pragma table_info(TABLENAME);` command returns information about a table and its fields. You don't need to edit this line, I just thought you might be curious! 41 | -------------------------------------------------------------------------------- /course/2-tables/exercises/1-create_table/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/2-tables/exercises/1-create_table/up.sql -------------------------------------------------------------------------------- /course/2-tables/exercises/1a-create_table/code.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 4 | 5 | pragma table_info('transactions'); 6 | -------------------------------------------------------------------------------- /course/2-tables/exercises/1a-create_table/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE transactions (id INTEGER, recipient_id INTEGER, sender_id INTEGER, note TEXT, amount INTEGER); 2 | 3 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 4 | 5 | pragma table_info('transactions'); 6 | -------------------------------------------------------------------------------- /course/2-tables/exercises/1a-create_table/readme.md: -------------------------------------------------------------------------------- 1 | # Create Table Practice 2 | 3 | In most relational databases a single table isn't enough to hold all the data we need! We *usually* create a table-per-entity. For example, a social media application might have the following tables: 4 | 5 | * `users` 6 | * `posts` 7 | * `comments` 8 | * `likes` 9 | 10 | ## Assignment 11 | 12 | We need a table that tracks the transactions between our *CashPal* users. 13 | 14 | Create the `transactions` table with the following fields: 15 | 16 | 1. id - `Integer` 17 | 2. recipient_id - `Integer` 18 | 3. sender_id - `Integer` 19 | 4. note - `Text` 20 | 5. amount - `Integer` 21 | -------------------------------------------------------------------------------- /course/2-tables/exercises/1a-create_table/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/2-tables/exercises/1a-create_table/up.sql -------------------------------------------------------------------------------- /course/2-tables/exercises/2-alter_table/code.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 4 | 5 | pragma table_info('users'); 6 | -------------------------------------------------------------------------------- /course/2-tables/exercises/2-alter_table/complete.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE people 2 | RENAME TO users; 3 | 4 | ALTER TABLE users 5 | RENAME COLUMN handle TO username; 6 | 7 | ALTER TABLE users 8 | ADD COLUMN password TEXT; 9 | 10 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 11 | 12 | pragma table_info('users'); 13 | -------------------------------------------------------------------------------- /course/2-tables/exercises/2-alter_table/readme.md: -------------------------------------------------------------------------------- 1 | # Altering Tables 2 | 3 | We often need to alter our database schema without deleting it and re-creating it. Imagine if Twitter deleted its database each time it needed to add a feature, that would be a *disaster*! Your account and all your tweets would be wiped out on a daily basis. 4 | 5 | Instead, we can use use the `ALTER TABLE` statement to make changes in place without deleting any data. 6 | 7 | ## ALTER TABLE 8 | 9 | With SQLite an `ALTER TABLE` statement allows you to: 10 | 11 | ### 1. Rename a table or column 12 | 13 | ```SQL 14 | ALTER TABLE employees 15 | RENAME TO contractors; 16 | 17 | ALTER TABLE contractors 18 | RENAME COLUMN salary TO invoice; 19 | ``` 20 | 21 | ### 2. ADD or DROP a column 22 | 23 | ```SQL 24 | ALTER TABLE contractors 25 | ADD COLUMN job_title TEXT; 26 | 27 | ALTER TABLE contractors 28 | DROP COLUMN is_manager; 29 | ``` 30 | 31 | ## Assignment 32 | 33 | We need to make some changes to the `people` table! At the moment, we have these five columns (shown as rows so we can display datatypes): 34 | 35 | | CID | NAME | TYPE | NOTNULL | DFLT VALUE | PK | 36 | | --- | -------- | ------- | ------- | ---------- | --- | 37 | | 0 | id | INTEGER | 0 | | 0 | 38 | | 1 | handle | TEXT | 0 | | 0 | 39 | | 2 | name | TEXT | 0 | | 0 | 40 | | 3 | age | INTEGER | 0 | | 0 | 41 | | 4 | balance | INTEGER | 0 | | 0 | 42 | | 5 | is_admin | BOOLEAN | 0 | | 0 | 43 | 44 | 1. Rename the table to `users` 45 | 2. Rename the `handle` column to `username`. 46 | 3. Add the `password` (TEXT) column. 47 | -------------------------------------------------------------------------------- /course/2-tables/exercises/2-alter_table/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE people ( 2 | id INTEGER, 3 | handle TEXT, 4 | name TEXT, 5 | age INTEGER, 6 | balance INTEGER, 7 | is_admin BOOLEAN 8 | ); 9 | -------------------------------------------------------------------------------- /course/2-tables/exercises/3-intro_to_migrations/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which of the following statements about migrations is FALSE?", 3 | "answers": [ 4 | "You can be fast and loose when writing migrations - a bad migration is easy to fix", 5 | "Migrations are incremental changes made to a database", 6 | "Well-written migrations are reversible", 7 | "A good migration takes into account any systems that rely on the existing schema" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/2-tables/exercises/3-intro_to_migrations/readme.md: -------------------------------------------------------------------------------- 1 | # Intro to Migrations 2 | 3 | A database [migration](https://en.wikipedia.org/wiki/Schema_migration) is a set of changes to a relational database. In fact, the `ALTER TABLE` statements we did in the last exercise were examples of migrations! 4 | 5 | Migrations are helpful when transitioning from one state to another, fixing mistakes, or adapting a database to changes. 6 | 7 | *Good* migrations are small, incremental and ideally *reversible* changes to a database. As you can imagine, when working with large databases, making changes can be scary! We have to be careful when writing database migrations so that we don't break any systems that depend on the old database schema. 8 | 9 | @[youtube](https://www.youtube.com/watch?v=iHIGUpEVN6Y) 10 | 11 | ## Example of a bad migration 12 | 13 | If the CashPal backend periodically runs a query like `SELECT * FROM people`, and we execute a database migration that alters the table name from `people` to `users` *without updating the code*, the application will break! It will try to grab data from a table that no longer exists. 14 | 15 | A simple solution to this problem would be to deploy new code that uses a new query: 16 | 17 | ```sql 18 | SELECT * FROM users; 19 | ``` 20 | 21 | And we would deploy that code to production *immediately* following the migration. 22 | -------------------------------------------------------------------------------- /course/2-tables/exercises/3a-intro_to_migrations/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Will database migrations often be coupled with application code updates?", 3 | "answers": [ 4 | "Yes", 5 | "No" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/2-tables/exercises/3a-intro_to_migrations/readme.md: -------------------------------------------------------------------------------- 1 | # Intro to Migrations 2 | 3 | A database [migration](https://en.wikipedia.org/wiki/Schema_migration) is a set of changes to a relational database. In fact, the `ALTER TABLE` statements we did in the last exercise were examples of migrations! 4 | 5 | Migrations are helpful when transitioning from one state to another, fixing mistakes, or adapting a database to changes. 6 | 7 | *Good* migrations are small, incremental and ideally *reversible* changes to a database. As you can imagine, when working with large databases, making changes can be scary! We have to be careful when writing database migrations so that we don't break any systems that depend on the old database schema. 8 | 9 | @[youtube](https://www.youtube.com/watch?v=iHIGUpEVN6Y) 10 | 11 | ## Example of a bad migration 12 | 13 | If the CashPal backend periodically runs a query like `SELECT * FROM people`, and we execute a database migration that alters the table name from `people` to `users` *without updating the code*, the application will break! It will try to grab data from a table that no longer exists. 14 | 15 | A simple solution to this problem would be to deploy new code that uses a new query: 16 | 17 | ```sql 18 | SELECT * FROM users; 19 | ``` 20 | 21 | And we would deploy that code to production *immediately* following the migration. 22 | -------------------------------------------------------------------------------- /course/2-tables/exercises/3b-intro_to_migrations/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Why are 'good' migrations written in a reversible manner?", 3 | "answers": [ 4 | "So that if something goes wrong, the changes can be rolled back", 5 | "They're not", 6 | "Because you should always roll back changes before applying new ones" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /course/2-tables/exercises/3b-intro_to_migrations/readme.md: -------------------------------------------------------------------------------- 1 | # Intro to Migrations 2 | 3 | A database [migration](https://en.wikipedia.org/wiki/Schema_migration) is a set of changes to a relational database. In fact, the `ALTER TABLE` statements we did in the last exercise were examples of migrations! 4 | 5 | Migrations are helpful when transitioning from one state to another, fixing mistakes, or adapting a database to changes. 6 | 7 | *Good* migrations are small, incremental and ideally *reversible* changes to a database. As you can imagine, when working with large databases, making changes can be scary! We have to be careful when writing database migrations so that we don't break any systems that depend on the old database schema. 8 | 9 | @[youtube](https://www.youtube.com/watch?v=iHIGUpEVN6Y) 10 | 11 | ## Example of a bad migration 12 | 13 | If the CashPal backend periodically runs a query like `SELECT * FROM people`, and we execute a database migration that alters the table name from `people` to `users` *without updating the code*, the application will break! It will try to grab data from a table that no longer exists. 14 | 15 | A simple solution to this problem would be to deploy new code that uses a new query: 16 | 17 | ```sql 18 | SELECT * FROM users; 19 | ``` 20 | 21 | And we would deploy that code to production *immediately* following the migration. 22 | -------------------------------------------------------------------------------- /course/2-tables/exercises/4-migration_practice/code.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 4 | 5 | pragma table_info('transactions'); 6 | -------------------------------------------------------------------------------- /course/2-tables/exercises/4-migration_practice/complete.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE transactions 2 | ADD COLUMN was_successful BOOLEAN; 3 | 4 | ALTER TABLE transactions 5 | ADD COLUMN transaction_type TEXT; 6 | 7 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 8 | 9 | pragma table_info('transactions'); 10 | -------------------------------------------------------------------------------- /course/2-tables/exercises/4-migration_practice/readme.md: -------------------------------------------------------------------------------- 1 | # Migration Practice 2 | 3 | When writing *reversible* migrations, we use the terms "up" and "down" migrations. An "up" migration is simply the set of changes you want to make, like altering/removing/adding/editing a table in some way. A "down" migration includes the changes that would *revert* any of the "up" migration's changes. 4 | 5 | ## Assignment 6 | 7 | Add additional columns to the `transactions` table. We want to know whether or not the transaction was successfully completed between two users. We also want our database to track the *type* of transaction. 8 | 9 | Our `transactions` table looks like this at the moment: 10 | 11 | | cid | name | type | notnull | dflt_value | pk | 12 | | --- | ------------ | ------- | ------- | ---------- | --- | 13 | | 0 | id | INTEGER | 0 | | 0 | 14 | | 1 | recipient_id | INTEGER | 0 | | 0 | 15 | | 2 | sender_id | INTEGER | 0 | | 0 | 16 | | 3 | note | TEXT | 0 | | 0 | 17 | | 4 | amount | INTEGER | 0 | | 0 | 18 | 19 | Complete the following `up` migration: 20 | 21 | * Add the `boolean` `was_successful` column to the `transactions` table. 22 | * Add the `TEXT` `transaction_type` column to the `transactions` table. 23 | -------------------------------------------------------------------------------- /course/2-tables/exercises/4-migration_practice/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE transactions ( 2 | id INTEGER, 3 | recipient_id INTEGER, 4 | sender_id INTEGER, 5 | note TEXT, 6 | amount INTEGER 7 | ); 8 | -------------------------------------------------------------------------------- /course/2-tables/exercises/5-datatypes/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "How is a 'true' boolean value stored and presented in SQLite?", 3 | "answers": [ 4 | "1", 5 | "0", 6 | "The string 'true'", 7 | "The string 'false'" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/2-tables/exercises/5-datatypes/readme.md: -------------------------------------------------------------------------------- 1 | # SQL Data Types 2 | 3 | SQL as a language can support many different data types. However, the datatypes that *your database management system ([DBMS](https://en.wikipedia.org/wiki/Database#:~:text=A%20database%20management%20system%20(DBMS)))* supports will vary depending on the specific database you're using. 4 | 5 | SQLite only supports the most *basic* types, and we're using SQLite in this course! 6 | 7 | ## SQLite Data Types 8 | 9 | Let's go over the [data types supported by SQLite:](https://www.sqlite.org/datatype3.html) and how they are stored. 10 | 11 | 1. `NULL` - Null value. 12 | 2. `INTEGER` - A signed integer stored in 0,1,2,3,4,6, or 8 bytes. 13 | 3. `REAL` - Floating point value stored as an 64-bit [IEEE floating point number](https://en.wikipedia.org/wiki/IEEE_754). 14 | 4. `TEXT` - Text string stored using database encoding such as [UTF-8](https://en.wikipedia.org/wiki/UTF-8) 15 | 5. `BLOB` - Short for [Binary large object](https://en.wikipedia.org/wiki/Binary_large_object) and typically used for images, audio or other multimedia. 16 | 17 | ## Boolean values 18 | 19 | It's important to note - SQLite does not have a separate `BOOLEAN` storage class. Instead, boolean values are stored as integers: 20 | 21 | * `0` = `false` 22 | * `1` = `true` 23 | 24 | *It's not actually all that weird, boolean values are just binary bits after all!* 25 | 26 | SQLite will still let you write your queries using `boolean` expressions and `true`/`false` keywords, but it will convert the booleans to integers under-the-hood. 27 | -------------------------------------------------------------------------------- /course/2-tables/exercises/5a-datatypes/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "All SQL databases support the same datatypes", 3 | "answers": [ 4 | "False", 5 | "True" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/2-tables/exercises/5a-datatypes/readme.md: -------------------------------------------------------------------------------- 1 | # SQL Data Types 2 | 3 | SQL as a language can support many different data types. However, the datatypes that *your database management system ([DBMS](https://en.wikipedia.org/wiki/Database#:~:text=A%20database%20management%20system%20(DBMS)))* supports will vary depending on the specific database you're using. 4 | 5 | SQLite only supports the most *basic* types, and we're using SQLite in this course! 6 | 7 | ## SQLite Data Types 8 | 9 | Let's go over the [data types supported by SQLite:](https://www.sqlite.org/datatype3.html) and how they are stored. 10 | 11 | 1. `NULL` - Null value. 12 | 2. `INTEGER` - A signed integer stored in 0,1,2,3,4,6, or 8 bytes. 13 | 3. `REAL` - Floating point value stored as an 64-bit [IEEE floating point number](https://en.wikipedia.org/wiki/IEEE_754). 14 | 4. `TEXT` - Text string stored using database encoding such as [UTF-8](https://en.wikipedia.org/wiki/UTF-8) 15 | 5. `BLOB` - Short for [Binary large object](https://en.wikipedia.org/wiki/Binary_large_object) and typically used for images, audio or other multimedia. 16 | 17 | ## Boolean values 18 | 19 | It's important to note - SQLite does not have a separate `BOOLEAN` storage class. Instead, boolean values are stored as integers: 20 | 21 | * `0` = `false` 22 | * `1` = `true` 23 | 24 | *It's not actually all that weird, boolean values are just binary bits after all!* 25 | 26 | SQLite will still let you write your queries using `boolean` expressions and `true`/`false` keywords, but it will convert the booleans to integers under-the-hood. 27 | -------------------------------------------------------------------------------- /course/2-tables/exercises/5b-datatypes/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "What type would you use to store a user's email?", 3 | "answers": [ 4 | "TEXT", 5 | "REAL", 6 | "INTEGER", 7 | "BLOB" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/2-tables/exercises/5b-datatypes/readme.md: -------------------------------------------------------------------------------- 1 | # SQL Data Types 2 | 3 | SQL as a language can support many different data types. However, the datatypes that *your database management system ([DBMS](https://en.wikipedia.org/wiki/Database#:~:text=A%20database%20management%20system%20(DBMS)))* supports will vary depending on the specific database you're using. 4 | 5 | SQLite only supports the most *basic* types, and we're using SQLite in this course! 6 | 7 | ## SQLite Data Types 8 | 9 | Let's go over the [data types supported by SQLite:](https://www.sqlite.org/datatype3.html) and how they are stored. 10 | 11 | 1. `NULL` - Null value. 12 | 2. `INTEGER` - A signed integer stored in 0,1,2,3,4,6, or 8 bytes. 13 | 3. `REAL` - Floating point value stored as an 64-bit [IEEE floating point number](https://en.wikipedia.org/wiki/IEEE_754). 14 | 4. `TEXT` - Text string stored using database encoding such as [UTF-8](https://en.wikipedia.org/wiki/UTF-8) 15 | 5. `BLOB` - Short for [Binary large object](https://en.wikipedia.org/wiki/Binary_large_object) and typically used for images, audio or other multimedia. 16 | 17 | ## Boolean values 18 | 19 | It's important to note - SQLite does not have a separate `BOOLEAN` storage class. Instead, boolean values are stored as integers: 20 | 21 | * `0` = `false` 22 | * `1` = `true` 23 | 24 | *It's not actually all that weird, boolean values are just binary bits after all!* 25 | 26 | SQLite will still let you write your queries using `boolean` expressions and `true`/`false` keywords, but it will convert the booleans to integers under-the-hood. 27 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/1-null_values/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/3-constraints/exercises/1-null_values/code.sql -------------------------------------------------------------------------------- /course/3-constraints/exercises/1-null_values/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * from transactions; -------------------------------------------------------------------------------- /course/3-constraints/exercises/1-null_values/readme.md: -------------------------------------------------------------------------------- 1 | # Null values 2 | 3 | In SQL, a cell with a `NULL` value indicates that the value is *missing*. A `NULL` value is *very* different from a *zero* value. 4 | 5 | ## Constraints 6 | 7 | When creating a table we can define whether or not a field *can* or *cannot* be `NULL`, and that's a kind of `constraint`. 8 | 9 | We will cover constraints in more detail soon, for now, let's focus on `NULL` values. 10 | 11 | ## Assignment 12 | 13 | We didn't force any constraints on our tables when we created them and it has allowed for `NULL` entries to make their way into our table! Let's take a look at our `transactions` table to see what those `NULL` values look like. 14 | 15 | Write a query to `SELECT` all of the fields on all records of the `transactions` table. 16 | 17 | ## Tip 18 | 19 | Use the `*` (wildcard) syntax to select *all* fields. 20 | 21 | ## Observe 22 | 23 | Notice that both the `transaction_type` and `was_successful` fields have `NULL` values in all 3 records in the table (nulls are represented by blank cells in our system). That's because we ran our migration in the previous exercise *after* the 3 records were created! 24 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/1-null_values/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE transactions ( 2 | id INTEGER, 3 | recipient_id INTEGER, 4 | sender_id INTEGER, 5 | note TEXT, 6 | amount INTEGER 7 | ); 8 | 9 | INSERT INTO transactions (id, recipient_id, sender_id, note, amount) 10 | VALUES (1, 14, 26, "Testing transaction!", 10.50); 11 | 12 | INSERT INTO transactions (id, sender_id) 13 | VALUES (2, 4); 14 | 15 | INSERT INTO transactions (recipient_id, note, amount) 16 | VALUES (5, "Oil change, full synthetic", 140.22); 17 | 18 | ALTER TABLE transactions 19 | ADD COLUMN transaction_type TEXT; 20 | 21 | ALTER TABLE transactions 22 | ADD COLUMN was_successful BOOLEAN; 23 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/2-constraints/code.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 4 | 5 | pragma table_info('users'); 6 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/2-constraints/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 12 | 13 | pragma table_info('users'); 14 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/2-constraints/readme.md: -------------------------------------------------------------------------------- 1 | # Constraints 2 | 3 | A `constraint` is a rule we create on a database that *enforces* some specific behavior. For example, setting a `NOT NULL` constraint on a column ensures that the column will not accept `NULL` values. 4 | 5 | If we try to insert a `NULL` value into a column with the `NOT NULL` constraint, the insert will fail with an error message. Constraints are extremely useful when we need to *ensure* that certain kinds of data exist within our database. 6 | 7 | ## Defining a NOT NULL constraint 8 | 9 | The `NOT NULL` constraint can be added directly to the `CREATE TABLE` statement. 10 | 11 | ```SQL 12 | CREATE TABLE employees( 13 | id INTEGER PRIMARY KEY, 14 | name TEXT UNIQUE, 15 | title TEXT NOT NULL 16 | ); 17 | ``` 18 | 19 | ## SQLite limitation 20 | 21 | In other dialects of SQL you can `ADD CONSTRAINT` within an `ALTER TABLE` statement. SQLite does *not* support this feature so when we create our tables we need to make sure we specify all the constraints we want! Here's a [list of SQL Features](https://www.sqlite.org/omitted.html) SQLite does not implement in case you're curious. 22 | 23 | ## Assignment 24 | 25 | Thankfully all the tables we have created for *CashPal* up to this point have been for testing purposes! Now that we have a better understanding of constraints, let's rebuild our database with the proper constraints and tables! 26 | 27 | Create the `USERS` table with the following fields and constraints: 28 | 29 | * `id` - `INTEGER`, `PRIMARY KEY` 30 | * `name` - `TEXT`, `NOT NULL` 31 | * `age` - `INTEGER`, `NOT NULL` 32 | * `country_code` - `TEXT`, `NOT NULL` 33 | * `username` - `TEXT`, `UNIQUE` 34 | * `password` - `TEXT`, `NOT NULL` 35 | * `is_admin` - `BOOLEAN` 36 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/2-constraints/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/3-constraints/exercises/2-constraints/up.sql -------------------------------------------------------------------------------- /course/3-constraints/exercises/3-primary_keys/code.sql: -------------------------------------------------------------------------------- 1 | INSERT into users ( 2 | id, 3 | name, 4 | age, 5 | username, 6 | password, 7 | is_admin 8 | ) values ( 9 | 0, 10 | "Rudolf", 11 | 33, 12 | "rudolf1234", 13 | "thisisnotsecure", 14 | false 15 | ); 16 | 17 | INSERT into users ( 18 | id, 19 | name, 20 | age, 21 | username, 22 | password, 23 | is_admin 24 | ) values ( 25 | 0, 26 | "Jerry", 27 | 25, 28 | "jerrysmith", 29 | "mypasswordis1234", 30 | true 31 | ); 32 | 33 | select * from users; 34 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/3-primary_keys/complete.sql: -------------------------------------------------------------------------------- 1 | INSERT into users ( 2 | id, 3 | name, 4 | age, 5 | username, 6 | password, 7 | is_admin 8 | ) values ( 9 | 0, 10 | "Rudolf", 11 | 33, 12 | "rudolf1234", 13 | "thisisnotsecure", 14 | false 15 | ); 16 | 17 | INSERT into users ( 18 | id, 19 | name, 20 | age, 21 | username, 22 | password, 23 | is_admin 24 | ) values ( 25 | 1, 26 | "Jerry", 27 | 25, 28 | "jerrysmith", 29 | "mypasswordis1234", 30 | true 31 | ); 32 | 33 | select * from users; 34 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/3-primary_keys/readme.md: -------------------------------------------------------------------------------- 1 | # Primary Keys 2 | 3 | A *key* defines and protects relationships between tables. A [`primary key`](https://en.wikipedia.org/wiki/Primary_key) is a special column that uniquely identifies records within a table. Each table can have one, and only one primary key. 4 | 5 | ## Your primary key will almost always be the "id" column 6 | 7 | It's *very* common to have a column named `id` on each table in a database, and that `id` is the primary key for that table. No two rows in that table can share an `id`. 8 | 9 | A `PRIMARY KEY` constraint can be explicitly specified on a column to ensure uniqueness, rejecting any inserts where you attempt to create a duplicate ID. 10 | 11 | ## Assignment 12 | 13 | Run the code. Notice that there's a bug - there is a violation of a `PRIMARY KEY` constraint on the `id` column. *Fix the data that's being inserted.* 14 | 15 | When working with integer ids, it's best practice to increment the `id` by `1` for each successive insert. Follow this convention when fixing the bug. 16 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/3-primary_keys/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | username TEXT UNIQUE, 6 | password TEXT NOT NULL, 7 | is_admin BOOLEAN 8 | ); 9 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/4-foreign_keys/code.sql: -------------------------------------------------------------------------------- 1 | INSERT into users ( 2 | id, 3 | name, 4 | country_code 5 | ) values ( 6 | 0, 7 | "Jerry", 8 | "US" 9 | ); 10 | 11 | INSERT into users ( 12 | id, 13 | name, 14 | country_code 15 | ) values ( 16 | 1, 17 | "Amit", 18 | "IND" 19 | ); 20 | 21 | /* -- DON'T TOUCH BELOW THIS LINE -- */ 22 | 23 | select * from users; 24 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/4-foreign_keys/complete.sql: -------------------------------------------------------------------------------- 1 | INSERT into users ( 2 | id, 3 | name, 4 | country_code 5 | ) values ( 6 | 0, 7 | "Jerry", 8 | "US" 9 | ); 10 | 11 | INSERT into users ( 12 | id, 13 | name, 14 | country_code 15 | ) values ( 16 | 1, 17 | "Amit", 18 | "IN" 19 | ); 20 | 21 | /* -- DON'T TOUCH BELOW THIS LINE -- */ 22 | 23 | select * from users; 24 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/4-foreign_keys/readme.md: -------------------------------------------------------------------------------- 1 | # Foreign Keys 2 | 3 | Foreign keys are what makes relational databases relational! Foreign keys define the relationships *between* tables. Simply put, a `FOREIGN KEY` is a field in one table that references another table's `PRIMARY KEY`. 4 | 5 | ## Creating a Foreign Key in SQLite 6 | 7 | Creating a `FOREIGN KEY` in SQLite happens at table creation! After we define the table fields and constraints we add an additional `CONSTRAINT` where we define the `FOREIGN KEY` and its `REFERENCES`. 8 | 9 | Here's an example: 10 | 11 | ```SQL 12 | CREATE TABLE departments ( 13 | id INTEGER PRIMARY KEY, 14 | department_name TEXT NOT NULL 15 | ); 16 | 17 | CREATE TABLE employees ( 18 | id INTEGER PRIMARY KEY, 19 | name TEXT NOT NULL, 20 | department_id INTEGER, 21 | CONSTRAINT fk_departments 22 | FOREIGN KEY (department_id) 23 | REFERENCES departments(id) 24 | ); 25 | ``` 26 | 27 | In this example, an `employee` has a `department_id`. The `department_id` must be the same as the `id` field of a record from the `departments` table. 28 | 29 | ## Assignment 30 | 31 | Our `users` table stores the country our users are from in a `country_code` field. We need some additional data about countries like their name, but we don't want to bloat our `users` table with all that country data. 32 | 33 | The "locations" team at CashPal has created a "countries" table, and we can link a user to their country by setting a foreign key in the `users` table. 34 | 35 | Take a look at the code. There's an issue with the `INSERT` statements again! Fix up the data so no foreign key constraints are violated. You'll need to reference the *setup* code below. 36 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/4-foreign_keys/up.sql: -------------------------------------------------------------------------------- 1 | PRAGMA foreign_keys = ON; 2 | 3 | CREATE table countries(code TEXT PRIMARY KEY, name TEXT); 4 | 5 | CREATE TABLE users ( 6 | id INTEGER PRIMARY KEY, 7 | name TEXT NOT NULL, 8 | age INTEGER, 9 | country_code TEXT NOT NULL, 10 | username TEXT , 11 | password TEXT, 12 | is_admin BOOLEAN, 13 | FOREIGN KEY (country_code) 14 | REFERENCES countries(code) 15 | ); 16 | 17 | INSERT into countries ( 18 | code, 19 | name 20 | ) values ( 21 | "US", 22 | "United States of America" 23 | ); 24 | 25 | INSERT into countries ( 26 | code, 27 | name 28 | ) values ( 29 | "IN", 30 | "India" 31 | ); 32 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/5-intro_to_schema/code.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* -- TEST SUITE. DON'T TOUCH BELOW THIS LINE -- */ 4 | 5 | pragma table_info('transactions'); 6 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/5-intro_to_schema/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE transactions ( 2 | id INTEGER PRIMARY KEY, 3 | sender_id INTEGER, 4 | recipient_id INTEGER, 5 | memo TEXT NOT NULL, 6 | amount INTEGER NOT NULL, 7 | balance INTEGER NOT NULL 8 | ); 9 | 10 | /* -- TEST SUITE. DON'T TOUCH BELOW THIS LINE -- */ 11 | 12 | pragma table_info('transactions'); 13 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/5-intro_to_schema/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/3-constraints/exercises/5-intro_to_schema/up.sql -------------------------------------------------------------------------------- /course/3-constraints/exercises/6-relational_databases/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "How many courses is Sam enrolled in?", 3 | "answers": [ 4 | "3", 5 | "1", 6 | "4", 7 | "5" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/6-relational_databases/readme.md: -------------------------------------------------------------------------------- 1 | # Relational Databases 2 | 3 | We have been using the term *relational* quite a bit, it's time we actually go over what that means! A *relational* database is a type of database that stores data so that it can be easily related to other data. For example, a `user` can have many `tweets`. There's a relationship between a `user` and their `tweet`. 4 | 5 | In a relational database: 6 | 7 | 1. Data is typically represented in "tables". 8 | 2. Each table has "columns" or "fields that hold attributes related to the record. 9 | 3. Each row or entry in the table is called a [record](https://en.wikipedia.org/wiki/Record_(computer_science)). 10 | 4. Typically, each record has a unique `Id` called the [primary key](https://en.wikipedia.org/wiki/Primary_key). 11 | 12 | ## Example Relational Database 13 | 14 | ![Relational Database](https://i.imgur.com/Ogx4ICa.jpg) 15 | 16 | Here is an example of a small relational database. This database has 3 tables, `Students`, `Courses`, and `StudentCourses`. The `StudentCourses` table manages the relationship between the `Students` and the `Courses` tables. 17 | 18 | ## Example 1: Sam 19 | 20 | * Sam has an `Id` of `1` 21 | * We can find Sam's courses by looking in the `StudentCourses` for the records that match his `StudentId`. 22 | 23 | ## Example 2: MongoDB 24 | 25 | * `MongoDB` has an `Id` of 3 26 | * We can find all the students enrolled in the MongoDB course by checking the `StudentCourses` table 27 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/6a-relational_databases/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "How many students are in the MongoDB course?", 3 | "answers": [ 4 | "3", 5 | "1", 6 | "4", 7 | "5" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/6a-relational_databases/readme.md: -------------------------------------------------------------------------------- 1 | # Relational Databases 2 | 3 | We have been using the term *relational* quite a bit, it's time we actually go over what that means! A *relational* database is a type of database that stores data so that it can be easily related to other data. For example, a `user` can have many `tweets`. There's a relationship between a `user` and their `tweet`. 4 | 5 | In a relational database: 6 | 7 | 1. Data is typically represented in "tables". 8 | 2. Each table has "columns" or "fields that hold attributes related to the record. 9 | 3. Each row or entry in the table is called a [record](https://en.wikipedia.org/wiki/Record_(computer_science)). 10 | 4. Typically, each record has a unique `Id` called the [primary key](https://en.wikipedia.org/wiki/Primary_key). 11 | 12 | ## Example Relational Database 13 | 14 | ![Relational Database](https://i.imgur.com/Ogx4ICa.jpg) 15 | 16 | Here is an example of a small relational database. This database has 3 tables, `Students`, `Courses`, and `StudentCourses`. The `StudentCourses` table manages the relationship between the `Students` and the `Courses` tables. 17 | 18 | ## Example 1: Sam 19 | 20 | * Sam has an `Id` of `1` 21 | * We can find Sam's courses by looking in the `StudentCourses` for the records that match his `StudentId`. 22 | 23 | ## Example 2: MongoDB 24 | 25 | * `MongoDB` has an `Id` of 3 26 | * We can find all the students enrolled in the MongoDB course by checking the `StudentCourses` table 27 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/7-relational_nonrelational/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Relational databases typically ____ duplicate data, while non-relational databases more often ____ duplicate data.", 3 | "answers": [ 4 | "do not, do", 5 | "do, do not" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/7-relational_nonrelational/readme.md: -------------------------------------------------------------------------------- 1 | # Relational vs Non-Relational Databases 2 | 3 | The big difference between relational and non-relational databases is that non-relational databases *nest* their data. Instead of keeping records on separate tables, they store records *within other records*. 4 | 5 | To over-simplify it, you can think of non-relational databases as giant JSON blobs. If a user can have multiple courses, you might just add all the courses to the user record. 6 | 7 | ```json 8 | { 9 | "users": [ 10 | { 11 | "id": 0, 12 | "name": "Elon", 13 | "courses": [ 14 | { 15 | "name": "Biology", 16 | "id": 0 17 | }, 18 | { 19 | "name": "Biology", 20 | "id": 0 21 | } 22 | ] 23 | } 24 | ] 25 | } 26 | ``` 27 | 28 | This often results in *duplicate data* within the database. That's obviously less than ideal, but it does have some benefits that we'll talk about later in the course. 29 | 30 | ## Relational database 31 | 32 | ![Relational Database](https://i.imgur.com/Ogx4ICa.jpg) 33 | 34 | ## Non-relational database 35 | 36 | ![relational vs non-relational](https://i.imgur.com/36gbplf.jpeg) 37 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/7a-relational_nonrelational/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Non relational databases connect similar entities by using ____", 3 | "answers": [ 4 | "Nested data", 5 | "Keys", 6 | "Concurrency", 7 | "Flubber" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/3-constraints/exercises/7a-relational_nonrelational/readme.md: -------------------------------------------------------------------------------- 1 | # Relational vs Non-Relational Databases 2 | 3 | The big difference between relational and non-relational databases is that non-relational databases *nest* their data. Instead of keeping records on separate tables, they store records *within other records*. 4 | 5 | To over-simplify it, you can think of non-relational databases as giant JSON blobs. If a user can have multiple courses, you might just add all the courses to the user record. 6 | 7 | ```json 8 | { 9 | "users": [ 10 | { 11 | "id": 0, 12 | "name": "Elon", 13 | "courses": [ 14 | { 15 | "name": "Biology", 16 | "id": 0 17 | }, 18 | { 19 | "name": "Biology", 20 | "id": 0 21 | } 22 | ] 23 | } 24 | ] 25 | } 26 | ``` 27 | 28 | This often results in *duplicate data* within the database. That's obviously less than ideal, but it does have some benefits that we'll talk about later in the course. 29 | 30 | ## Relational database 31 | 32 | ![Relational Database](https://i.imgur.com/Ogx4ICa.jpg) 33 | 34 | ## Non-relational database 35 | 36 | ![relational vs non-relational](https://i.imgur.com/36gbplf.jpeg) 37 | -------------------------------------------------------------------------------- /course/4-crud/exercises/1-what_is_crud/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/4-crud/exercises/1-what_is_crud/code.sql -------------------------------------------------------------------------------- /course/4-crud/exercises/1-what_is_crud/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM crud; 2 | -------------------------------------------------------------------------------- /course/4-crud/exercises/1-what_is_crud/hint.md: -------------------------------------------------------------------------------- 1 | # Hint 2 | 3 | *Reading* data is just another way of saying *retrieving* data! We can use a SQL `SELECT` statement to *retrieve* or *read* data from a table! 4 | -------------------------------------------------------------------------------- /course/4-crud/exercises/1-what_is_crud/readme.md: -------------------------------------------------------------------------------- 1 | # CRUD 2 | 3 | CRUD is an acronym that stands for `CREATE`, `READ`, `UPDATE`, and `DELETE`. These four operations are the bread and butter of nearly every database you will create. 4 | 5 | ## HTTP and CRUD 6 | 7 | The CRUD operations correlate nicely with the HTTP methods we learned in the [Learn HTTP](https://boot.dev/learn/learn-http) course. 8 | 9 | * `HTTP POST` - `CREATE` 10 | * `HTTP GET` - `READ` 11 | * `HTTP PUT` - `UPDATE` 12 | * `HTTP DELETE` - `DELETE` 13 | 14 | ## Assignment 15 | 16 | We've created a table for you called `crud`, it's a toy table we're using for interview practice at CashPal. 17 | 18 | Determine which SQL command can be used for a `READ` operation and use it to *read* all the fields in all the records in the `crud` table! 19 | -------------------------------------------------------------------------------- /course/4-crud/exercises/1-what_is_crud/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE crud (c TEXT, r TEXT, u TEXT, d TEXT); 2 | INSERT INTO crud (c, r, u, d) 3 | VALUES ("CREATE = CREATE", "READ = SELECT", "UPDATE = UPDATE", "DELETE = DELETE"); 4 | -------------------------------------------------------------------------------- /course/4-crud/exercises/10-delete_danger/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "You should ____ have automated backups being taken of a production database", 3 | "answers": [ 4 | "Almost always", 5 | "Never", 6 | "Sometimes", 7 | "Almost never" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/4-crud/exercises/10-delete_danger/readme.md: -------------------------------------------------------------------------------- 1 | # The danger of deleting data 2 | 3 | Deleting data can be a dangerous operation. Once removed, data can be really hard if not *impossible* to restore! Let's talk about a couple of common ways back-end engineers protect against losing valuable customer data. 4 | 5 | @[youtube](https://www.youtube.com/watch?v=kCWHniEnQDM) 6 | 7 | ## Strategy 1 - Backups 8 | 9 | If you're using a cloud-service like GCP's [Cloud SQL](https://cloud.google.com/sql) or AWS's [RDS](https://aws.amazon.com/rds/) you should *always* turn on automated backups. They take an automatic snapshot of your entire database on some interval, and keep it around for some length of time. 10 | 11 | For example, the Boot.dev database has a backup snapshot taken daily and we retain those backups for 30 days. If I ever accidentally run a query that deletes valuable data, I can restore it from the backup. 12 | 13 | **You should have a backup strategy for production databases.** 14 | 15 | ## Strategy 2 - Soft deletes 16 | 17 | A "soft delete" is when you don't *actually* delete data from your database, but instead just "mark" the data as deleted. For example, you might set a `deleted_at` date on the row you want to delete. Then, in your queries you ignore anything that has a `deleted_at` date set. The idea is that this allows your application to behave as if it's deleting data, but you can always go back and restore any data that's been removed. 18 | 19 | You should probably only soft-delete if you have a specific reason to do so. Automated backups should be "good enough" for most applications that are just interested in protecting against developer mistakes. 20 | -------------------------------------------------------------------------------- /course/4-crud/exercises/10a-delete_danger/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "A soft-delete is where you ____", 3 | "answers": [ 4 | "Mark a row as deleted instead of actually removing the data", 5 | "Delete data from a snapshot", 6 | "Delete some data, but it's not actually removed from the database for 30 days", 7 | "Delete some data by asking your database in a nice soothing voice. Usually with a 'please'." 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/4-crud/exercises/10a-delete_danger/readme.md: -------------------------------------------------------------------------------- 1 | # The danger of deleting data 2 | 3 | Deleting data can be a dangerous operation. Once removed, data can be really hard if not *impossible* to restore! Let's talk about a couple of common ways back-end engineers protect against losing valuable customer data. 4 | 5 | @[youtube](https://www.youtube.com/watch?v=kCWHniEnQDM) 6 | 7 | ## Strategy 1 - Backups 8 | 9 | If you're using a cloud-service like GCP's [Cloud SQL](https://cloud.google.com/sql) or AWS's [RDS](https://aws.amazon.com/rds/) you should *always* turn on automated backups. They take an automatic snapshot of your entire database on some interval, and keep it around for some length of time. 10 | 11 | For example, the Boot.dev database has a backup snapshot taken daily and we retain those backups for 30 days. If I ever accidentally run a query that deletes valuable data, I can restore it from the backup. 12 | 13 | **You should have a backup strategy for production databases.** 14 | 15 | ## Strategy 2 - Soft deletes 16 | 17 | A "soft delete" is when you don't *actually* delete data from your database, but instead just "mark" the data as deleted. For example, you might set a `deleted_at` date on the row you want to delete. Then, in your queries you ignore anything that has a `deleted_at` date set. The idea is that this allows your application to behave as if it's deleting data, but you can always go back and restore any data that's been removed. 18 | 19 | You should probably only soft-delete if you have a specific reason to do so. Automated backups should be "good enough" for most applications that are just interested in protecting against developer mistakes. 20 | -------------------------------------------------------------------------------- /course/4-crud/exercises/11-update/code.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 4 | 5 | SELECT * from users WHERE id = 9; 6 | -------------------------------------------------------------------------------- /course/4-crud/exercises/11-update/complete.sql: -------------------------------------------------------------------------------- 1 | UPDATE users 2 | SET is_admin = true 3 | WHERE id = 9 ; 4 | 5 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 6 | 7 | SELECT * from users WHERE id = 9; 8 | -------------------------------------------------------------------------------- /course/4-crud/exercises/11-update/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 12 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 15 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 18 | VALUES (3, 'John', 39, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 21 | VALUES (4, 'Ram', 42, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 24 | VALUES (5, 'Hunter', 30, 'US', 'Hdev92', 'backendDev', false); 25 | 26 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 27 | VALUES (6, 'Allan', 27, 'US', 'Alires', 'iLoveB00tdev', true); 28 | 29 | INSERT INTO users(name, age, country_code, username, password, is_admin) 30 | VALUES ('Lance', 20, 'US', 'LanChr', 'b00tdevisbest', false); 31 | 32 | INSERT INTO users(name, age, country_code, username, password, is_admin) 33 | VALUES ('Tiffany', 28, 'US', 'Tifferoon', 'autoincrement', true); 34 | 35 | INSERT INTO users(name, age, country_code, username, password, is_admin) 36 | VALUES ('Lane', 27, 'US', 'wagslane', 'update_me', false); 37 | -------------------------------------------------------------------------------- /course/4-crud/exercises/12-orm/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "When using an ORM, you ____", 3 | "answers": [ 4 | "Call methods and functions made available via the ORM's API", 5 | "Write a lot of raw SQL" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/4-crud/exercises/12a-orm/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "One advantage of an ORM is that it...", 3 | "answers": [ 4 | "Makes your code less verbose", 5 | "Ensures faster queries", 6 | "Gives you more control over your database", 7 | "Is easier to debug at a low-level" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/4-crud/exercises/12b-orm/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Should you use an ORM?", 3 | "answers": [ 4 | "It depends on the project/team", 5 | "Almost always", 6 | "Almost never", 7 | "Always" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/4-crud/exercises/2-create/code.sql: -------------------------------------------------------------------------------- 1 | -- ? 2 | 3 | 4 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 5 | 6 | SELECT * FROM users; 7 | 8 | -------------------------------------------------------------------------------- /course/4-crud/exercises/2-create/complete.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 2 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 3 | 4 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 5 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 6 | 7 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 8 | 9 | SELECT * FROM users; 10 | 11 | -------------------------------------------------------------------------------- /course/4-crud/exercises/2-create/readme.md: -------------------------------------------------------------------------------- 1 | # Insert Statement 2 | 3 | Tables are pretty useless without data in them! In SQL we can add records to a table using an `INSERT INTO` statement. When using an `INSERT` statement we must first specify the `table` we are inserting the record into, followed by the `fields` within that table we want to add `VALUES` to. 4 | 5 | Example `INSERT INTO` statement: 6 | 7 | ```SQL 8 | INSERT INTO employees(id, name, title) 9 | VALUES (1, 'Allan', 'Engineer'); 10 | ``` 11 | 12 | ## Assignment 13 | 14 | Let's start manually adding some of the records to our `users` table! 15 | 16 | Take a look at the `CREATE TABLE` statement in the *setup code* below for the `users` table structure, and use that information to insert the following records into the table: 17 | 18 | ### Record 1 19 | 20 | * `id`: 1 21 | * `name`: David 22 | * `age`: 34 23 | * `country_code`: US 24 | * `username`: DavidDev 25 | * `password`: insertPractice 26 | * `is_admin`: false 27 | 28 | ### Record 2 29 | 30 | * `id`: 2 31 | * `name`: Samantha 32 | * `age`: 29 33 | * `country_code`: BR 34 | * `username`: Sammy93 35 | * `password`: addingRecords! 36 | * `is_admin`: false 37 | -------------------------------------------------------------------------------- /course/4-crud/exercises/2-create/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | -------------------------------------------------------------------------------- /course/4-crud/exercises/2-http_create/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "A front-end typically communicates with a database directly to add new records.", 3 | "answers": [ 4 | "False", 5 | "True" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/4-crud/exercises/2-http_create/readme.md: -------------------------------------------------------------------------------- 1 | # HTTP CRUD Database lifecycle 2 | 3 | It's important to understand how data *flows* through a typical web application. 4 | 5 | ![database flow](https://i.imgur.com/hli3crD.png) 6 | 7 | 1. The front-end processes some data from user input - maybe a form is submitted. 8 | 2. The front-end sends that data to the server through an HTTP request - maybe a `POST`. 9 | 3. The server makes a SQL query to it's database to create an associated record - Probably using an `INSERT` statement. 10 | 4. Once the server has processed that the database query was successful, it responds to the front-end with a status code! Hopefully a 200-level code (success)! 11 | -------------------------------------------------------------------------------- /course/4-crud/exercises/2a-http_create/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "The 'Create' in CRUD maps to which SQL statement and HTTP Method?", 3 | "answers": [ 4 | "INSERT, POST", 5 | "SELECT, PUT", 6 | "INSERT, GET", 7 | "SELECT, GET" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/4-crud/exercises/2a-http_create/readme.md: -------------------------------------------------------------------------------- 1 | # HTTP CRUD Database lifecycle 2 | 3 | It's important to understand how data *flows* through a typical web application. 4 | 5 | ![database flow](https://i.imgur.com/hli3crD.png) 6 | 7 | 1. The front-end processes some data from user input - maybe a form is submitted. 8 | 2. The front-end sends that data to the server through an HTTP request - maybe a `POST`. 9 | 3. The server makes a SQL query to it's database to create an associated record - Probably using an `INSERT` statement. 10 | 4. Once the server has processed that the database query was successful, it responds to the front-end with a status code! Hopefully a 200-level code (success)! 11 | -------------------------------------------------------------------------------- /course/4-crud/exercises/3-autoincrement/code.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 4 | 5 | SELECT * FROM users; 6 | -------------------------------------------------------------------------------- /course/4-crud/exercises/3-autoincrement/complete.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO users(name, age, country_code, username, password, is_admin) 2 | VALUES ('Lance', 20, 'US', 'LanChr', 'b00tdevisbest', false); 3 | 4 | INSERT INTO users(name, age, country_code, username, password, is_admin) 5 | VALUES ('Tiffany', 28, 'US', 'Tifferoon', 'autoincrement', true); 6 | 7 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 8 | 9 | SELECT * FROM users; 10 | -------------------------------------------------------------------------------- /course/4-crud/exercises/3-autoincrement/readme.md: -------------------------------------------------------------------------------- 1 | # Auto increment 2 | 3 | Many dialects of SQL support an `AUTO INCREMENT` feature. When inserting records into a table with `AUTO INCREMENT` enabled, the database will assign the next value *automatically*. In SQLite an integer `id` field that has the `PRIMARY KEY` constraint will auto increment by default! 4 | 5 | ## Id's 6 | 7 | Depending on how your database is set up, you may be using traditional `id`s or you may be using [UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier). SQL doesn't support auto incrementing a `uuid` so if your database is using them your server will have to handle the changing uuid's for each record. 8 | 9 | ## Using `AUTO INCREMENT` in SQLite 10 | 11 | We are using traditional `id`s in our database, so we can take advantage of the auto increment feature. Different dialects of SQL will implement this feature differently, but in SQLite any `id` field that has the `PRIMARY KEY` constraint will auto increment! So we can omit the `id` field within the `INSERT` statement and allow the database to automatically add that field for us! 12 | 13 | ## Assignment 14 | 15 | Let's add some more records but allow the database to automatically increment the `id` field. Add the following records to the database: 16 | 17 | ### Record 1 18 | 19 | * `name`: Lance 20 | * `age`: 20 21 | * `country_code`: US 22 | * `username`: LanChr 23 | * `password`: b00tdevisbest 24 | * `is_admin`: false 25 | 26 | ### Record 2 27 | 28 | * `name`: Tiffany 29 | * `age`: 28 30 | * `country_code`: US 31 | * `username`: Tifferoon 32 | * `password`: autoincrement 33 | * `is_admin`: true 34 | -------------------------------------------------------------------------------- /course/4-crud/exercises/3-autoincrement/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 12 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 15 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 18 | VALUES (3, 'John', 39, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 21 | VALUES (4, 'Ram', 42, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 24 | VALUES (5, 'Hunter', 30, 'US', 'Hdev92', 'backendDev', false); 25 | 26 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 27 | VALUES (6, 'Allan', 27, 'US', 'Alires', 'iLoveB00tdev', true); 28 | -------------------------------------------------------------------------------- /course/4-crud/exercises/4-manual_entry/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Every time someone creates an account on boot.dev Allan or Lane has to manually add them to the database by hand-writing a SQL query", 3 | "answers": [ 4 | "False", 5 | "True" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/4-crud/exercises/4-manual_entry/readme.md: -------------------------------------------------------------------------------- 1 | # Manual Entry 2 | 3 | Manually `INSERT`ing every single record in a database would be an *extremely* time-consuming task! Working with raw SQL as we are now is *not* super common when designing backend systems. 4 | 5 | When working with SQL within a software system, like a backend web application, you'll typically have access to a programming language such as Go or Python. For example, a backend server written in Go can use string concatenation to dynamically create SQL statements, and that's usually how it's done! 6 | 7 | ```go 8 | sqlQuery := fmt.Sprintf(` 9 | INSERT INTO users(name, age, country_code) 10 | VALUES ('%s', %v, %s); 11 | `, user.Name, user.Age, user.CountryCode) 12 | ``` 13 | 14 | ## SQL Injection 15 | 16 | The example above is an oversimplification of what *really* happens when you access a database using Go code. In essence, it's correct. String interpolation is how production systems access databases. That said, it must be done *carefully* to not be a [security vulnerability](https://en.wikipedia.org/wiki/SQL_injection). We'll talk more about that later! 17 | -------------------------------------------------------------------------------- /course/4-crud/exercises/4a-manual_entry/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Within backend systems, SQL queries are typically ____", 3 | "answers": [ 4 | "Generated by code", 5 | "Written by hand" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/4-crud/exercises/4a-manual_entry/readme.md: -------------------------------------------------------------------------------- 1 | # Manual Entry 2 | 3 | Manually `INSERT`ing every single record in a database would be *extremely* time consuming task! Working with raw SQL as we are now is *not* super common when designing backend systems. 4 | 5 | When working with SQL within a software system, like a backend web application, you'll typically have access to a programming language such as Go or Python. For example, a backend server written in Go can use string concatenation to dynamically create SQL statements, and that's usually how it's done! 6 | 7 | ```go 8 | sqlQuery := fmt.Sprintf(` 9 | INSERT INTO users(name, age, country_code) 10 | VALUES ('%s', %v, %s); 11 | `, user.Name, user.Age, user.CountryCode) 12 | ``` 13 | 14 | ## SQL Injection 15 | 16 | The example above is an oversimplification of what really happens when you access a database using Go code. In essence, it's correct. String interpolation is how production systems access databases. That said, it must be done *carefully* so as to not be a [security vulnerability](https://en.wikipedia.org/wiki/SQL_injection). We'll talk more about that later! 17 | -------------------------------------------------------------------------------- /course/4-crud/exercises/5-count/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/4-crud/exercises/5-count/code.sql -------------------------------------------------------------------------------- /course/4-crud/exercises/5-count/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT count(*) from users; -------------------------------------------------------------------------------- /course/4-crud/exercises/5-count/readme.md: -------------------------------------------------------------------------------- 1 | # Count 2 | 3 | We can use a `SELECT` statement to get a *count* of the records within a table. This can be very useful when we need to know *how many* records there are, but we don't particularly care what's in them. 4 | 5 | Here's an example in SQLite: 6 | 7 | ```SQL 8 | SELECT count(*) from employees; 9 | ``` 10 | 11 | The `*` in this case refers to a column name. We don't care about the count of a *specific column* - we want to know the number of *total records* so we can use the wildcard (*). 12 | 13 | ## Assignment 14 | 15 | Here is the current state of our `users` table: 16 | 17 | | id | name | age | country_code | username | password | is_admin | 18 | | --- | -------- | --- | ------------ | --------- | ------------------ | -------- | 19 | | 1 | David | 34 | US | DavidDev | insertPractice | 0 | 20 | | 2 | Samantha | 29 | BR | Sammy93 | addingRecords! | 0 | 21 | | 3 | John | 39 | CA | Jjdev21 | welovebootdev | 0 | 22 | | 4 | Ram | 42 | IN | Ram11c | thisSQLcourserocks | 0 | 23 | | 5 | Hunter | 30 | US | Hdev92 | backendDev | 0 | 24 | | 6 | Allan | 27 | US | Alires | iLoveB00tdev | 1 | 25 | | 7 | Lance | 20 | US | LanChr | b00tdevisbest | 0 | 26 | | 8 | Tiffany | 28 | US | Tifferoon | autoincrement | 1 | 27 | 28 | Our business strategy team at CashPal wants to know how many users of the app we have. We can't use the `id` number to calculate the count because user accounts can be deleted! 29 | 30 | Use a `count` statement to retrieve the number of records in the `users` table. 31 | -------------------------------------------------------------------------------- /course/4-crud/exercises/5-count/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 12 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 15 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 18 | VALUES (3, 'John', 39, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 21 | VALUES (4, 'Ram', 42, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 24 | VALUES (5, 'Hunter', 30, 'US', 'Hdev92', 'backendDev', false); 25 | 26 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 27 | VALUES (6, 'Allan', 27, 'US', 'Alires', 'iLoveB00tdev', true); 28 | 29 | INSERT INTO users(name, age, country_code, username, password, is_admin) 30 | VALUES ('Lance', 20, 'US', 'LanChr', 'b00tdevisbest', false); 31 | 32 | INSERT INTO users(name, age, country_code, username, password, is_admin) 33 | VALUES ('Tiffany', 28, 'US', 'Tifferoon', 'autoincrement', true); 34 | -------------------------------------------------------------------------------- /course/4-crud/exercises/6-http_read/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "The HTTP Method that generally corresponds with a SQL SELECT statement is an HTTP", 3 | "answers": [ 4 | "GET", 5 | "PUT", 6 | "PATCH", 7 | "UPDATE" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/4-crud/exercises/6-http_read/readme.md: -------------------------------------------------------------------------------- 1 | # HTTP CRUD database lifecycle 2 | 3 | We talked about how a "create" operation flows through a web application. Let's talk about a "read". 4 | 5 | ![read lifecycle](https://i.imgur.com/KTDQGy1.png) 6 | 7 | Let's talk through an example using the CashPal app. Our product manager wants to show profile data on a user's settings page. Here's how we could engineer that feature request: 8 | 9 | 1. First, the front-end webpage loads. 10 | 2. The front-end sends an HTTP `GET` request to a `/users` endpoint on the back-end server. 11 | 3. The server receives the request. 12 | 4. The server uses a `SELECT` statement to retrieve the user's record from the `users` table in the database. 13 | 5. The server converts the row of SQL data into a `JSON` object and sends it back to the front-end. 14 | -------------------------------------------------------------------------------- /course/4-crud/exercises/6a-http_read/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which happens first?", 3 | "answers": [ 4 | "A GET request is made", 5 | "A SELECT statement is executed", 6 | "A JSON response is sent" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /course/4-crud/exercises/6a-http_read/readme.md: -------------------------------------------------------------------------------- 1 | # HTTP CRUD database lifecycle 2 | 3 | We talked about how a "create" operation flows through a web application. Let's talk about a "read". 4 | 5 | ![read lifecycle](https://i.imgur.com/KTDQGy1.png) 6 | 7 | Let's talk through an example using the CashPal app. Our product manager wants to show profile data on a user's settings page. Here's how we could engineer that feature request: 8 | 9 | 1. First, the front-end webpage loads. 10 | 2. The front-end sends an HTTP `GET` request to a `/users` endpoint on the back-end server. 11 | 3. The server receives the request. 12 | 4. The server uses a `SELECT` statement to retrieve the user's record from the `users` table in the database. 13 | 5. The server converts the row of SQL data into a `JSON` object and sends it back to the front-end. 14 | -------------------------------------------------------------------------------- /course/4-crud/exercises/7-where_clause/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/4-crud/exercises/7-where_clause/code.sql -------------------------------------------------------------------------------- /course/4-crud/exercises/7-where_clause/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT username from users WHERE is_admin = true; 2 | -------------------------------------------------------------------------------- /course/4-crud/exercises/7-where_clause/readme.md: -------------------------------------------------------------------------------- 1 | # WHERE clause 2 | 3 | In order to keep learning about CRUD operations in SQL, we need to learn how to make the instructions we send to the database more specific. SQL accepts a `WHERE` statement within a query that allows us to be very specific with our instructions. 4 | 5 | If we were unable to specify the specific record we wanted to `READ`, `UPDATE`, or `DELETE` making queries to a database would be very frustrating, and very inefficient. 6 | 7 | ## Using a WHERE clause 8 | 9 | Say we had *over 9000* records in our `users` table. We often want to look at specific user data within that table without retrieving *all* the other records in the table. We can use a `SELECT` statement followed by a `WHERE` clause to specify which records to retrieve. The `SELECT` statement stays the same, we just *add* the `WHERE` clause to the end of the `SELECT`. Here's an example: 10 | 11 | ```SQL 12 | SELECT name FROM users WHERE power_level >= 9000; 13 | ``` 14 | 15 | This will select only the `name` field of any user within the `users` table `WHERE` the `power_level` field is greater than or equal to `9000`. 16 | 17 | ## Assignment 18 | 19 | We need to know the `username` of all the users in our `users` table that have admin privileges! Retrieve them. 20 | -------------------------------------------------------------------------------- /course/4-crud/exercises/7-where_clause/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 12 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 15 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 18 | VALUES (3, 'John', 39, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 21 | VALUES (4, 'Ram', 42, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 24 | VALUES (5, 'Hunter', 30, 'US', 'Hdev92', 'backendDev', false); 25 | 26 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 27 | VALUES (6, 'Allan', 27, 'US', 'Alires', 'iLoveB00tdev', true); 28 | 29 | INSERT INTO users(name, age, country_code, username, password, is_admin) 30 | VALUES ('Lance', 20, 'US', 'LanChr', 'b00tdevisbest', false); 31 | 32 | INSERT INTO users(name, age, country_code, username, password, is_admin) 33 | VALUES ('Tiffany', 28, 'US', 'Tifferoon', 'autoincrement', true); 34 | -------------------------------------------------------------------------------- /course/4-crud/exercises/8-where_null/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/4-crud/exercises/8-where_null/code.sql -------------------------------------------------------------------------------- /course/4-crud/exercises/8-where_null/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * from transactions where sender_id IS NOT NULL; 2 | -------------------------------------------------------------------------------- /course/4-crud/exercises/8-where_null/readme.md: -------------------------------------------------------------------------------- 1 | # Finding NULL values 2 | 3 | You can use a `WHERE` clause to filter values by whether or not they're `NULL`. 4 | 5 | ## IS NULL 6 | 7 | ```SQL 8 | SELECT name FROM users WHERE first_name IS NULL; 9 | ``` 10 | 11 | ## IS NOT NULL 12 | 13 | ```SQL 14 | SELECT name FROM users WHERE first_name IS NOT NULL; 15 | ``` 16 | 17 | ## Assignment 18 | 19 | The way we store transactions at CashPal is interesting. We store a `user_id` field on the `transactions` table. That user is the "owner" of the transaction, and a `user_id` is never null. 20 | 21 | Whenever the owner of the transaction *receives* money, the `sender_id` will not be null - it will be the user id of the sender. The `recipient_id` will be null. 22 | 23 | Whenever the owner of the transaction *sends* money, the `recipient_id` will not be null - it will be the user id of the recipient. The `sender_id` will be null. 24 | 25 | **Select all the rows from the transactions table where the owner of the transactions is receiving money.** 26 | -------------------------------------------------------------------------------- /course/4-crud/exercises/8-where_null/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE transactions ( 2 | id INTEGER PRIMARY KEY, 3 | user_id INTEGER, 4 | recipient_id INTEGER, 5 | sender_id INTEGER, 6 | amount INTEGER 7 | ); 8 | 9 | INSERT INTO transactions(user_id, recipient_id, sender_id, amount) 10 | VALUES (1, 2, NULL, -10); 11 | INSERT INTO transactions(user_id, recipient_id, sender_id, amount) 12 | VALUES (1, NULL, 2, 25); 13 | INSERT INTO transactions(user_id, recipient_id, sender_id, amount) 14 | VALUES (1, 5, NULL, -20); 15 | INSERT INTO transactions(user_id, recipient_id, sender_id, amount) 16 | VALUES (1, NULL, 3, 10); 17 | -------------------------------------------------------------------------------- /course/4-crud/exercises/9-delete/code.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 4 | 5 | SELECT * from users; 6 | -------------------------------------------------------------------------------- /course/4-crud/exercises/9-delete/complete.sql: -------------------------------------------------------------------------------- 1 | DELETE from users 2 | WHERE id = 2; 3 | 4 | -- TEST SUITE, DON'T TOUCH BELOW THIS LINE -- 5 | 6 | SELECT * from users; 7 | -------------------------------------------------------------------------------- /course/4-crud/exercises/9-delete/readme.md: -------------------------------------------------------------------------------- 1 | # DELETE 2 | 3 | When a user deletes their account on Twitter, or deletes a comment on a YouTube video, that data needs to be removed from its respective database. 4 | 5 | ## DELETE statement 6 | 7 | A `DELETE` statement removes a record from a table that match the `WHERE` clause. As an example: 8 | 9 | ```SQL 10 | DELETE from employees 11 | WHERE id = 251; 12 | ``` 13 | 14 | This `DELETE` statement removes all records from the `employees` table that have an id of `251`! 15 | 16 | ## Assignment 17 | 18 | Samantha, one of our *CashPal* users, has opted to delete her account and stop using our app... which makes us sad. Anyways, we need to remove her record from the database! 19 | 20 | Delete Samantha's record from the user table. 21 | 22 | ### Current state of the `users` table 23 | 24 | | ID | NAME | AGE | country_code | USERNAME | PASSWORD | is_admin | 25 | | --- | -------- | --- | ------------ | --------- | ------------------ | -------- | 26 | | 1 | David | 34 | US | DavidDev | insertPractice | 0 | 27 | | 2 | Samantha | 29 | BR | Sammy93 | addingRecords! | 0 | 28 | | 3 | John | 39 | CA | Jjdev21 | welovebootdev | 0 | 29 | | 4 | Ram | 42 | IN | Ram11c | thisSQLcourserocks | 0 | 30 | | 5 | Hunter | 30 | US | Hdev92 | backendDev | 0 | 31 | | 6 | Allan | 27 | US | Alires | iLoveB00tdev | 1 | 32 | | 7 | Lance | 20 | US | LanChr | b00tdevisbest | 0 | 33 | | 8 | Tiffany | 28 | US | Tifferoon | autoincrement | 1 | 34 | | 9 | Lane | 27 | US | wagslane | update_me | 0 | 35 | -------------------------------------------------------------------------------- /course/4-crud/exercises/9-delete/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 12 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 15 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 18 | VALUES (3, 'John', 39, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 21 | VALUES (4, 'Ram', 42, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 24 | VALUES (5, 'Hunter', 30, 'US', 'Hdev92', 'backendDev', false); 25 | 26 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 27 | VALUES (6, 'Allan', 27, 'US', 'Alires', 'iLoveB00tdev', true); 28 | 29 | INSERT INTO users(name, age, country_code, username, password, is_admin) 30 | VALUES ('Lance', 20, 'US', 'LanChr', 'b00tdevisbest', false); 31 | 32 | INSERT INTO users(name, age, country_code, username, password, is_admin) 33 | VALUES ('Tiffany', 28, 'US', 'Tifferoon', 'autoincrement', true); 34 | 35 | INSERT INTO users(name, age, country_code, username, password, is_admin) 36 | VALUES ('Lane', 27, 'US', 'wagslane', 'update_me', false); 37 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/1-as_clause/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/5-basic_queries/exercises/1-as_clause/code.sql -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/1-as_clause/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT amount, note as birthday_message from transactions 2 | WHERE sender_id = 10; 3 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/1-as_clause/readme.md: -------------------------------------------------------------------------------- 1 | # As Clause in SQL 2 | 3 | Sometimes we need to structure the data we return from our queries in a specific way. An `AS` clause allows us to "alias" a piece of data in our query. The alias only exists for the duration of the query. 4 | 5 | ## As keyword 6 | 7 | The following queries return the same data: 8 | 9 | ```SQL 10 | SELECT employee_id AS id, employee_name AS name 11 | FROM employees; 12 | ``` 13 | 14 | ```SQL 15 | SELECT employee_id, employee_name 16 | FROM employees; 17 | ``` 18 | 19 | The difference is that the results from the aliased query would have column names `id` and `name` instead of `employee_id` and `employee_name`. 20 | 21 | ## Assignment 22 | 23 | A user has asked us to find all the transactions on their account from their grandma. We thought it would be fun to rename the `note` field to `birthday_message` because we noticed all the transactions from grandma are birthday messages. 24 | 25 | Return the `amount` and the `note` field (renamed to `birthday_message`) from the `transactions` table where the `sender_id` is `10` (grandma). 26 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/1-as_clause/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE transactions ( 2 | id INTEGER PRIMARY KEY, 3 | user_id INTEGER NOT NULL, 4 | recipient_id INTEGER, 5 | sender_id INTEGER, 6 | note TEXT, 7 | amount INTEGER, 8 | was_successful BOOLEAN 9 | ); 10 | 11 | INSERT INTO transactions (user_id, sender_id, note, amount, was_successful) 12 | VALUES (2, 10, "Happy Birthday! Gramma loves you!", 20.00, true); 13 | 14 | INSERT INTO transactions (user_id, sender_id, note, amount, was_successful) 15 | VALUES (2, 10, "Happy Birthday from Gramma!", 20.00, true); 16 | 17 | INSERT INTO transactions (user_id,sender_id, note, amount, was_successful) 18 | VALUES (2, 2, "Car problems", 256.21, true); 19 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/2-functions/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/5-basic_queries/exercises/2-functions/code.sql -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/2-functions/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT *, 2 | IIF(was_successful = true, "No action required", "Perform an audit") AS audit 3 | FROM transactions; 4 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/2-functions/readme.md: -------------------------------------------------------------------------------- 1 | # SQL Functions 2 | 3 | At the end of the day, SQL is a programming language, and it's one that supports functions. We can use functions and aliases to *calculate* new columns in a query. This is similar to how you might use formulas in excel. 4 | 5 | ## IIF function 6 | 7 | In SQLite, the `IIF` function works like a [ternary](https://book.pythontips.com/en/latest/ternary_operators.html). For example, 8 | 9 | ```SQL 10 | IIF(carA > carB, "Car a is bigger", "Car b is bigger") 11 | ``` 12 | 13 | If `a` is greater than `b`, this statement evaluates to the string `"Car a is bigger"`. Otherwise, it evaluates to `"Car b is bigger"`. 14 | 15 | Here's how we can use `IIF()` and a `directive` alias to add a new calculated column to our result set: 16 | 17 | ```SQL 18 | SELECT quantity, 19 | IIF(quantity < 10, "Order more", "In Stock") AS directive 20 | from products 21 | ``` 22 | 23 | ## Assignment 24 | 25 | We need to look through *CashPal*'s transaction data and determine whether or not any of the transactions need to be audited. 26 | 27 | Return all the data from the `transactions` table, and add an extra column at the end called `audit`. 28 | 29 | * If a row's `was_successful` field is `true`, the `audit` field should say "No action required". 30 | * If a row's `was_successful` field is `false`, the `audit` field should say "Perform an audit". 31 | 32 | ## Tip 33 | 34 | Some equality operators in SQL: 35 | 36 | * `=`: Equal to 37 | * `<`: Less than 38 | * `>`: Greater than 39 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/2-functions/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE transactions ( 2 | id INTEGER, 3 | recipient_id INTEGER, 4 | sender_id INTEGER, 5 | note TEXT, 6 | amount INTEGER, 7 | was_successful BOOLEAN 8 | ); 9 | 10 | INSERT INTO transactions (id, recipient_id, sender_id, note, amount, was_successful) 11 | VALUES (1, 9, 4, "Testing transaction!", 10.50, true); 12 | 13 | INSERT INTO transactions (id, recipient_id, sender_id, note, amount, was_successful) 14 | VALUES (2, 5, 10, "Thanks for lunch!", 9.56, true); 15 | 16 | INSERT INTO transactions (id, recipient_id, sender_id, note, amount, was_successful) 17 | VALUES (3, 6, 2, "Car problems", 256.21, true); 18 | 19 | INSERT INTO transactions (id, recipient_id, sender_id, note, amount, was_successful) 20 | VALUES (4, 7, 8, "Happy birthday!!", 50, true); 21 | 22 | INSERT INTO transactions (id, recipient_id, sender_id, note, amount, was_successful) 23 | VALUES (5, 9, 11, "MTG Draft", 50, false); 24 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/3-between/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/5-basic_queries/exercises/3-between/code.sql -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/3-between/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT name, age 2 | FROM users 3 | WHERE age BETWEEN 18 and 30; -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/3-between/readme.md: -------------------------------------------------------------------------------- 1 | # Between 2 | 3 | We can check if values are `between` two numbers using the `WHERE` clause in an intuitive way! The `WHERE` clause doesn't always have to be used to specify specific id's or values. We can also use it to help narrow down our result set. Here's an example: 4 | 5 | ```SQL 6 | SELECT employee_name, salary 7 | FROM employees 8 | WHERE salary BETWEEN 30000 and 60000; 9 | ``` 10 | 11 | This query returns all the employees `name` and `salary` fields for any rows where the `salary` is `BETWEEN` 30,000 and 60,000! We can also query results that are `NOT BETWEEN` two specified values. 12 | 13 | ```SQL 14 | SELECT product_name, quantity 15 | FROM products 16 | WHERE quantity NOT BETWEEN 20 and 100; 17 | ``` 18 | 19 | This query returns all the product names where the quantity was not between `20` and `100`. We can use conditionals to make the results of our query as specific as we need them to be. 20 | 21 | ## Assignment 22 | 23 | We need to see how many young adults are using *CashPal*! 24 | 25 | Query our `users` table to find all the `name` and `age` fields of users `BETWEEN` the age of `18` and `30`. 26 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/3-between/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 12 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 15 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 18 | VALUES (3, 'John', 39, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 21 | VALUES (4, 'Ram', 42, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 24 | VALUES (5, 'Hunter', 30, 'US', 'Hdev92', 'backendDev', false); 25 | 26 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 27 | VALUES (6, 'Allan', 27, 'US', 'Alires', 'iLoveB00tdev', true); 28 | 29 | INSERT INTO users(name, age, country_code, username, password, is_admin) 30 | VALUES ('Lance', 20, 'US', 'LanChr', 'b00tdevisbest', false); 31 | 32 | INSERT INTO users(name, age, country_code, username, password, is_admin) 33 | VALUES ('Tiffany', 28, 'US', 'Tifferoon', 'autoincrement', true); 34 | 35 | INSERT INTO users(name, age, country_code, username, password, is_admin) 36 | VALUES ('Lane', 27, 'US', 'wagslane', 'update_me', false); 37 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/3-distinct/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/5-basic_queries/exercises/3-distinct/code.sql -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/3-distinct/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT country_code 2 | FROM users; -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/3-distinct/readme.md: -------------------------------------------------------------------------------- 1 | # Distinct 2 | 3 | Sometimes we want to retrieve records from a table without getting back any duplicates. 4 | 5 | For example, we may want to know all the different companies our employees have worked at previously, but we don't want to see the same company multiple times in the report. 6 | 7 | ## SELECT DISTINCT 8 | 9 | SQL offers us the `DISTINCT` keyword that removes duplicate records from the resulting query. 10 | 11 | ```SQL 12 | SELECT DISTINCT previous_company 13 | FROM employees; 14 | ``` 15 | 16 | This only returns one row for each unique `previous_company` value. 17 | 18 | ## Assignment 19 | 20 | *CashPal* executives want to know how many countries we have customers in. We store `country_code` data as a column on the `users` table. 21 | 22 | Run a `DISTINCT` query to get all the unique `country_code`s from the `users` table. 23 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/3-distinct/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 12 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 15 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 18 | VALUES (3, 'John', 39, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 21 | VALUES (4, 'Ram', 42, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 24 | VALUES (5, 'Hunter', 30, 'US', 'Hdev92', 'backendDev', false); 25 | 26 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 27 | VALUES (6, 'Allan', 27, 'US', 'Alires', 'iLoveB00tdev', true); 28 | 29 | INSERT INTO users(name, age, country_code, username, password, is_admin) 30 | VALUES ('Lance', 20, 'US', 'LanChr', 'b00tdevisbest', false); 31 | 32 | INSERT INTO users(name, age, country_code, username, password, is_admin) 33 | VALUES ('Tiffany', 28, 'US', 'Tifferoon', 'autoincrement', true); 34 | 35 | INSERT INTO users(name, age, country_code, username, password, is_admin) 36 | VALUES ('Lane', 27, 'US', 'wagslane', 'update_me', false); 37 | 38 | INSERT INTO users(name, age, country_code, username, password, is_admin) 39 | VALUES ('Darren', 15, 'CA', 'Dshan', 'found_me', false); 40 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/4-and/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/5-basic_queries/exercises/4-and/code.sql -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/4-and/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM users 3 | WHERE country_code IN ('CA') 4 | AND age < 18; 5 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/4-and/readme.md: -------------------------------------------------------------------------------- 1 | # Logical Operators - AND 2 | 3 | We often need to use *multiple* conditions to retrieve the exact information we want. We can begin to structure much more complex queries by using multiple conditions together to narrow down the search results of our query. 4 | 5 | The logical `AND` operator can be used to narrow down our result sets even more! 6 | 7 | ## AND operator 8 | 9 | ```SQL 10 | SELECT product_name, quantity, shipment_status 11 | FROM products 12 | WHERE shipment_status = 'pending' 13 | AND quantity BETWEEN 0 and 10; 14 | ``` 15 | 16 | This only retrieves records where *both* the `shipment_status` is "pending" *AND* the `quantity` is between `0` and `10`. 17 | 18 | ## Equality operators 19 | 20 | All of the following operators are supported in SQL. The `=` is the main one to watch out for, it's not `==` like in many other languages! 21 | 22 | * `=` 23 | * `<` 24 | * `>` 25 | * `<=` 26 | * `>=` 27 | 28 | ## Assignment 29 | 30 | The legal restrictions in Canada have changed! The way we have to handle Canadian minors' CashPal transactions is more strict. We need to find all of those users, so we can see how many users this change affects! 31 | 32 | Write a query that retrieves all of the fields from the `users` table who are from Canada (`CA`), and are under the age of `18`. 33 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/4-and/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 12 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 15 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 18 | VALUES (3, 'John', 39, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 21 | VALUES (4, 'Ram', 42, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 24 | VALUES (5, 'Hunter', 30, 'US', 'Hdev92', 'backendDev', false); 25 | 26 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 27 | VALUES (6, 'Allan', 27, 'US', 'Alires', 'iLoveB00tdev', true); 28 | 29 | INSERT INTO users(name, age, country_code, username, password, is_admin) 30 | VALUES ('Lance', 20, 'US', 'LanChr', 'b00tdevisbest', false); 31 | 32 | INSERT INTO users(name, age, country_code, username, password, is_admin) 33 | VALUES ('Tiffany', 28, 'US', 'Tifferoon', 'autoincrement', true); 34 | 35 | INSERT INTO users(name, age, country_code, username, password, is_admin) 36 | VALUES ('Calliou', 4, 'CA', 'calliou123', 'tooSecure', false); 37 | 38 | INSERT INTO users(name, age, country_code, username, password, is_admin) 39 | VALUES ('Lane', 27, 'US', 'wagslane', 'update_me', true); 40 | 41 | INSERT INTO users(name, age, country_code, username, password, is_admin) 42 | VALUES ('Darren', 15, 'CA', 'Dshan', 'found_me', false); 43 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/5-or/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/5-basic_queries/exercises/5-or/code.sql -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/5-or/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT count(*) 2 | FROM users 3 | WHERE (country_code = ('US') OR country_code = ('CA')) 4 | AND age < 18; 5 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/5-or/readme.md: -------------------------------------------------------------------------------- 1 | # OR 2 | 3 | As you've probably guessed, if the logical `AND` operator is supported, the `OR` operator is probably supported as well. 4 | 5 | ```SQL 6 | SELECT product_name, quantity, shipment_status 7 | FROM products 8 | WHERE shipment_status = 'out of stock' 9 | OR quantity BETWEEN 10 and 100; 10 | ``` 11 | 12 | This query retrieves records where *either* the shipment_status `condition` *OR* the `quantity` condition are met. 13 | 14 | ## Order of operations 15 | 16 | You can group logical operations with parentheses to specify the [order of operations](https://www.mathsisfun.com/operation-order-pemdas.html). 17 | 18 | ```sql 19 | (this AND that) OR the_other 20 | ``` 21 | 22 | ## Assignment 23 | 24 | The laws have changed again! Now we need to see how many affected users meet this criteria: 25 | 26 | > Users who are from the United States or Canada, and are under 18 27 | 28 | Write a query that retrieves the *count* of every user that matches the conditions above. 29 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/5-or/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 12 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 15 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 18 | VALUES (3, 'John', 39, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 21 | VALUES (4, 'Ram', 42, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 24 | VALUES (5, 'Rain', 14, 'IN', 'Ram11c76', 'loveThePass', false); 25 | 26 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 27 | VALUES (6, 'Hunter', 17, 'US', 'Hdev92', 'backendDev', false); 28 | 29 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 30 | VALUES (7, 'Allan', 27, 'US', 'Alires', 'iLoveB00tdev', true); 31 | 32 | INSERT INTO users(name, age, country_code, username, password, is_admin) 33 | VALUES ('Lance', 20, 'US', 'LanChr', 'b00tdevisbest', false); 34 | 35 | INSERT INTO users(name, age, country_code, username, password, is_admin) 36 | VALUES ('Tiffany', 15, 'US', 'Tifferoon', 'autoincrement', true); 37 | 38 | INSERT INTO users(name, age, country_code, username, password, is_admin) 39 | VALUES ('Lane', 27, 'US', 'wagslane', 'update_me', true); 40 | 41 | INSERT INTO users(name, age, country_code, username, password, is_admin) 42 | VALUES ('Darren', 15, 'CA', 'Dshan', 'found_me', false); 43 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/6-in/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/5-basic_queries/exercises/6-in/code.sql -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/6-in/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT name, age, country_code 2 | FROM users 3 | WHERE country_code IN ('US', 'CA', 'MX'); 4 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/6-in/readme.md: -------------------------------------------------------------------------------- 1 | # In 2 | 3 | Another variation to the `WHERE` clause we can utilize is the `IN` operator. `IN` returns `true` or `false` if the first operand matches *any* of the values in the second operand. The `IN` operator is a shorthand for multiple `OR` conditions. 4 | 5 | These two queries are equivalent: 6 | 7 | ```SQL 8 | SELECT product_name, shipment_status 9 | FROM products 10 | WHERE shipment_status IN ('shipped', 'preparing', 'out of stock'); 11 | ``` 12 | 13 | ```SQL 14 | SELECT product_name, shipment_status 15 | FROM products 16 | WHERE shipment_status = 'shipped' 17 | OR shipment_status = 'preparing' 18 | OR shipment_status = 'out of stock'; 19 | ``` 20 | 21 | Hopefully, you're starting to see how querying specific data using fine-tuned SQL clauses helps reveal important insights! The larger a table becomes the harder it becomes to analyze without proper queries. 22 | 23 | ## Assignment 24 | 25 | We want to know which of our users are from North America. Write a `SELECT` statement that returns the `name` `age` and `country_code` fields for every user within the `US`, `CA` or `MX`. 26 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/6-in/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 12 | VALUES (1, 'David', 34, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 15 | VALUES (2, 'Samantha', 29, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 18 | VALUES (3, 'John', 39, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 21 | VALUES (4, 'Ram', 42, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 24 | VALUES (5, 'Hunter', 30, 'MX', 'Hdev92', 'backendDev', false); 25 | 26 | INSERT INTO users(id, name, age, country_code, username, password, is_admin) 27 | VALUES (6, 'Allan', 27, 'US', 'Alires', 'iLoveB00tdev', true); 28 | 29 | INSERT INTO users(name, age, country_code, username, password, is_admin) 30 | VALUES ('Lance', 20, 'FR', 'LanChr', 'b00tdevisbest', false); 31 | 32 | INSERT INTO users(name, age, country_code, username, password, is_admin) 33 | VALUES ('Tiffany', 28, 'US', 'Tifferoon', 'autoincrement', true); 34 | 35 | INSERT INTO users(name, age, country_code, username, password, is_admin) 36 | VALUES ('Lane', 27, 'IN', 'wagslane', 'update_me', true); 37 | 38 | INSERT INTO users(name, age, country_code, username, password, is_admin) 39 | VALUES ('Darren', 15, 'CA', 'Dshan', 'found_me', false); 40 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/7-like_percent/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/5-basic_queries/exercises/7-like_percent/code.sql -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/7-like_percent/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * from users 2 | WHERE name LIKE 'Al%'; -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/7-like_percent/hint.md: -------------------------------------------------------------------------------- 1 | # Hint 2 | 3 | The `LIKE` operator expects a `string`! Make sure the statement you are comparing against is wrapped in quotes or SQL will think you're referring to a column! -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/7-like_percent/readme.md: -------------------------------------------------------------------------------- 1 | # Like 2 | 3 | Sometimes we don't have the luxury of knowing *exactly* what it is we need to query. Have you ever wanted to look up a song or a video but you only remember *part* of the name? SQL provides us an option for when we're in situations `LIKE` this. 4 | 5 | The `LIKE` keyword allows for the use of the `%` and `_` wildcard operators. Let's focus on `%` first. 6 | 7 | ## % Operator 8 | 9 | The `%` operator will match zero or more characters. We can use this operator within our query string to find more than just exact matches depending on where we place it. 10 | 11 | ## Product starts with "banana": 12 | 13 | ```SQL 14 | SELECT * FROM products 15 | WHERE product_name LIKE 'banana%'; 16 | ``` 17 | 18 | ## Product ends with "banana": 19 | 20 | ```SQL 21 | SELECT * from products 22 | WHERE product_name LIKE '%banana'; 23 | ``` 24 | 25 | ## Product contains "banana": 26 | 27 | ```SQL 28 | SELECT * from products 29 | WHERE product_name LIKE '%banana%'; 30 | ``` 31 | 32 | ## Assignment 33 | 34 | Our HR team is dealing with a ticket from one of our users but they are having trouble pulling up their record in the database. They are pretty sure the user's name starts with `Al`. 35 | 36 | Write a query that returns all the fields for records where the user's `name` starts with `Al`. 37 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/8-like_underscore/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/5-basic_queries/exercises/8-like_underscore/code.sql -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/8-like_underscore/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * from users 2 | WHERE name LIKE 'Al___'; 3 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/8-like_underscore/readme.md: -------------------------------------------------------------------------------- 1 | # Underscore Operator 2 | 3 | As discussed, the `%` wildcard operator matches zero or more characters. Meanwhile, the `_` wildcard operator only matches a *single* character. 4 | 5 | ```SQL 6 | SELECT * FROM products 7 | WHERE product_name LIKE '_oot'; 8 | ``` 9 | 10 | The query above matches products like: 11 | 12 | * boot 13 | * root 14 | * foot 15 | 16 | ```SQL 17 | SELECT * FROM products 18 | WHERE product_name LIKE '__oot'; 19 | ``` 20 | 21 | The query above matches products like: 22 | 23 | * shoot 24 | * groot 25 | 26 | ## Assignment 27 | 28 | HR has been able to narrow down their query further! They want a report of all user's whose names that start with `Al` *and are exactly 5 characters long*. 29 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/9-like_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which describes the values that match example 1?", 3 | "answers": [ 4 | "Values that start with 'or', and are at least 3 characters in length.", 5 | "Values that end with 'or', and are at least 3 characters in length.", 6 | "Values that start with 'or', and have 3 characters exactly.", 7 | "Values that end in 'or', and have 3 characters exactly." 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/9-like_quiz/readme.md: -------------------------------------------------------------------------------- 1 | # Wildcards quiz 2 | 3 | ## Example 1 4 | 5 | ```sql 6 | SELECT * from users 7 | WHERE name LIKE 'or_%'; 8 | ``` 9 | 10 | ## Example 2 11 | 12 | ```sql 13 | SELECT * from users 14 | WHERE name LIKE '__ing'; 15 | ``` 16 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/9a-like_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which would not match example 2?", 3 | "answers": [ 4 | "singing", 5 | "thing", 6 | "bling", 7 | "sling" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/5-basic_queries/exercises/9a-like_quiz/readme.md: -------------------------------------------------------------------------------- 1 | # Wildcards quiz 2 | 3 | ## Example 1 4 | 5 | ```sql 6 | SELECT * from users 7 | WHERE name LIKE 'or_%'; 8 | ``` 9 | 10 | ## Example 2 11 | 12 | ```sql 13 | SELECT * from users 14 | WHERE name LIKE '__ing'; 15 | ``` 16 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/1-limit/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/6-structuring_return_data/exercises/1-limit/code.sql -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/1-limit/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * from transactions 2 | WHERE note LIKE '%lunch%' 3 | LIMIT 5; -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/1-limit/readme.md: -------------------------------------------------------------------------------- 1 | # LIMIT 2 | 3 | Sometimes we don't want to retrieve *every* record from a table. For example, it's common for a production database table to have millions of rows, and `SELECT`ing all of them might crash your system! *The `LIMIT` keyword has entered the chat.* 4 | 5 | The `LIMIT` keyword can be used at the end of a select statement to reduce the number of records returned. 6 | 7 | ```SQL 8 | SELECT * FROM products 9 | WHERE product_name LIKE '%berry%' 10 | LIMIT 50; 11 | ``` 12 | 13 | The query above retrieves all the records from the `products` table where the name contains the word *berry*. If we ran this query on the Facebook database, it would almost certainly return a *lot* of records. 14 | 15 | The `LIMIT` statement only allows the database to return *up to* 50 records matching the query. This means that if there aren't that many records matching the query, the `LIMIT` statement will not have an effect. 16 | 17 | ## Assignment 18 | 19 | A lot of our users have been using *CashPal* to pay other users for lunch. Let's take a look at a *sample* of that data. 20 | 21 | Write a query that returns all rows and fields from the `transactions` table: 22 | 23 | * Any record where the `note` field has the word *lunch* in it. 24 | * The query should return at most `5` records. 25 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/2-limit_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "'LIMIT 5' will always return 5 records", 3 | "answers": [ 4 | "False", 5 | "True" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/2-limit_quiz/readme.md: -------------------------------------------------------------------------------- 1 | # Limit Quiz 2 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/2a-limit_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Why might you use a LIMIT clause?", 3 | "answers": [ 4 | "To avoid selecting a huge amount of data and causing strain on the system", 5 | "To get as much data as possible", 6 | "I wouldn't. System performance is an OPS person's problem", 7 | "Because I'm a 'machine learning engineer' and don't care about efficiency" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/2a-limit_quiz/readme.md: -------------------------------------------------------------------------------- 1 | # Limit Quiz 2 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/3-order_by/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/6-structuring_return_data/exercises/3-order_by/code.sql -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/3-order_by/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * from transactions 2 | WHERE amount BETWEEN 10 and 80 3 | ORDER BY amount desc; 4 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/3-order_by/readme.md: -------------------------------------------------------------------------------- 1 | # Order By 2 | 3 | SQL also offers us the ability to sort the results of a query using `ORDER BY`. By default, the `ORDER BY` keyword sorts records by the given field in ascending order, or `ASC` for short. However, `ORDER BY` does support descending order as well with the keyword `DESC`. 4 | 5 | ## Examples 6 | 7 | This query returns the `name`, `price`, and `quantity` fields from the `products` table sorted by `price` in *ascending* order: 8 | 9 | ```SQL 10 | SELECT name, price, quantity FROM products 11 | ORDER BY price; 12 | ``` 13 | 14 | This query returns the `name`, `price`, and `quantity` of the products ordered by the quantity in *descending* order: 15 | 16 | ```SQL 17 | SELECT name, price, quantity FROM products 18 | ORDER BY quantity desc; 19 | ``` 20 | 21 | ## Assignment 22 | 23 | Write a query that lists all the records in the `transactions` table where: 24 | 25 | * `amount` is `BETWEEN` 10 and 80 dollars. 26 | * The results are sorted by `amount` in *descending* order. 27 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/4-order_by_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Example 1 is sorted in ____ order", 3 | "answers": [ 4 | "DESC", 5 | "ASC" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/4-order_by_quiz/readme.md: -------------------------------------------------------------------------------- 1 | # Order By Quiz 2 | 3 | ## Example 1 4 | 5 | | name | age | 6 | | ------- | --- | 7 | | Preston | 30 | 8 | | Lane | 27 | 9 | | Rory | 22 | 10 | | Ashley | 20 | 11 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/4a-order_by_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which query would potentially return the data in example 1?", 3 | "answers": [ 4 | "SELECT * from people ORDER BY age DESC", 5 | "SELECT * from people ORDER BY age", 6 | "SELECT * from people ORDER BY DESC age", 7 | "SELECT * from people ORDER BY age ASC" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/4a-order_by_quiz/readme.md: -------------------------------------------------------------------------------- 1 | # Order By Quiz 2 | 3 | ## Example 1 4 | 5 | | name | age | 6 | | ------- | --- | 7 | | Preston | 30 | 8 | | Lane | 27 | 9 | | Rory | 22 | 10 | | Ashley | 20 | 11 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/5-order_limit/code.sql: -------------------------------------------------------------------------------- 1 | SELECT * from transactions 2 | WHERE amount BETWEEN 10 and 80 3 | LIMIT 4 4 | ORDER BY amount desc; 5 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/5-order_limit/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * from transactions 2 | WHERE amount BETWEEN 10 and 80 3 | ORDER BY amount desc 4 | LIMIT 4; 5 | -------------------------------------------------------------------------------- /course/6-structuring_return_data/exercises/5-order_limit/readme.md: -------------------------------------------------------------------------------- 1 | # Order By and Limit 2 | 3 | When using both `ORDER BY` and `LIMIT`, the `ORDER BY` clause must come *first*. 4 | 5 | ## Assignment 6 | 7 | An HR employee got into the Git repository where we store all the queries and tried to update one himself. 8 | 9 | Fix the bug in the SQL query. 10 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/1-count/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/7-aggregations/exercises/1-count/code.sql -------------------------------------------------------------------------------- /course/7-aggregations/exercises/1-count/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT count(*) 2 | FROM transactions 3 | WHERE user_id = 6 and was_successful = true; 4 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/1-count/readme.md: -------------------------------------------------------------------------------- 1 | # What are aggregations? 2 | 3 | An "aggregation" is a *single* value that's derived by combining *several* other values. We performed an aggregation earlier when we used the `count` statement to count the number of records in a table.. 4 | 5 | ## Why aggregations? 6 | 7 | Data stored in a database should generally be stored [raw](https://wagslane.dev/posts/keep-your-data-raw-at-rest/). When we need to calculate some additional data from the raw data, we can use an *aggregation*. 8 | 9 | Take the following `count` aggregation as an example: 10 | 11 | ```SQL 12 | SELECT COUNT(*) 13 | FROM products 14 | WHERE quantity = 0; 15 | ``` 16 | 17 | This query returns the number of products that have a `quantity` of `0`. We *could* store a count of the products in a separate database table, and increment/decrement it whenever we make changes to the `products` table - but that would be *redundant*. 18 | 19 | It's *much simpler* to store the products in a single place (we call this a [single source of truth](https://en.wikipedia.org/wiki/Single_source_of_truth)) and run an aggregation when we need to derive additional information from the raw data. 20 | 21 | ## Assignment 22 | 23 | The front-end team is building a dashboard page in *CashPal*. We need to be able to provide them the number of successful transactions for a given user. 24 | 25 | Return the number of `transactions` where the `user_id` is `6`, and `was_successful` is `true`. 26 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/2-sum/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/7-aggregations/exercises/2-sum/code.sql -------------------------------------------------------------------------------- /course/7-aggregations/exercises/2-sum/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT sum(amount) 2 | FROM transactions 3 | WHERE user_id = 9; -------------------------------------------------------------------------------- /course/7-aggregations/exercises/2-sum/readme.md: -------------------------------------------------------------------------------- 1 | # Sum 2 | 3 | The `sum` aggregation function returns the sum of a set of values. 4 | 5 | For example, the query below returns a single record containing a single field. The returned value is equal to the *total* salary being collected by all of the `employees` in the `employees` table. 6 | 7 | ```SQL 8 | SELECT sum(salary) 9 | FROM employees; 10 | ``` 11 | 12 | Which returns: 13 | 14 | | SUM(SALARY) | 15 | | ----------- | 16 | | 2483 | 17 | 18 | ## Assignment 19 | 20 | We need to be able to calculate the current balance for a given user because we don't (yet) store the running balance on each individual transaction record. 21 | 22 | Write a query that returns the `sum` aggregation of the `amount`s for all of Bob's transactions (`user_id` is `9`). 23 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/3-max/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/7-aggregations/exercises/3-max/code.sql -------------------------------------------------------------------------------- /course/7-aggregations/exercises/3-max/complete.sql: -------------------------------------------------------------------------------- 1 | select user_id, max(amount) 2 | from transactions 3 | where user_id = 4 and sender_id is NOT NULL; -------------------------------------------------------------------------------- /course/7-aggregations/exercises/3-max/readme.md: -------------------------------------------------------------------------------- 1 | # MAX 2 | 3 | As you may expect, the `max` function retrieves the *largest* value from a set of values. For example: 4 | 5 | ```SQL 6 | SELECT max(price) 7 | FROM products 8 | ``` 9 | 10 | This query looks through all of the prices in the `products` table and returns the price with the largest price value. Remember it only returns the `price`, not the rest of the record! You always need to specify each field you want a query to return. 11 | 12 | ## Assignment 13 | 14 | Use a `max` aggregation to find the largest amount of money *received* by a Jill (`user_id` of 4). Return her `user_id` and that amount. 15 | 16 | Table name: `transactions` 17 | 18 | Column names: 19 | 20 | * `id` 21 | * `user_id` 22 | * `recipient_id` 23 | * `sender_id` 24 | * `note` 25 | * `amount` 26 | * `was_successful` 27 | 28 | ## A note on schema 29 | 30 | * The `sender_id` will be present for any transactions where the user in question (`user_id`) is *receiving* money (from the sender). 31 | * The `recipient_id` will be present for any transactions where the user in question (`user_id`) is *sending* money (to the recipient). 32 | 33 | In other words, a transaction can only have a `sender_id` *or* a `recipient_id` - not *both*. The presence of one or the other indicates whether money is going *into* or *out of* the user's account. 34 | 35 | This `user_id`, `recipient_id`, `sender_id` schema we've designed is only *one* way to design a transactions database - there are other valid ways to do it! It's the one we're using, and later we'll talk more about the tradeoffs in different database design options. 36 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/4-min/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/7-aggregations/exercises/4-min/code.sql -------------------------------------------------------------------------------- /course/7-aggregations/exercises/4-min/complete.sql: -------------------------------------------------------------------------------- 1 | select min(age) 2 | from users 3 | where country_code = 'US'; 4 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/4-min/readme.md: -------------------------------------------------------------------------------- 1 | # Min 2 | 3 | The `min` function works the same as the `max` function but finds the *lowest* value instead of the *highest* value. 4 | 5 | ```SQL 6 | SELECT product_name, min(price) 7 | from products; 8 | ``` 9 | 10 | This query returns the `product_name` and the `price` fields of the record with the lowest `price`. 11 | 12 | ## Assignment 13 | 14 | Use a `min` aggregation to find the `age` of our youngest *CashPal* user in the United States in the `users` table. 15 | 16 | ## Users table 17 | 18 | ``` 19 | | id | name | age | country_code | username | password | is_admin | 20 | ``` 21 | 22 | * The `country_code` of the United States is `US`. 23 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/5-group_by/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/7-aggregations/exercises/5-group_by/code.sql -------------------------------------------------------------------------------- /course/7-aggregations/exercises/5-group_by/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT user_id, sum(amount) as balance 2 | FROM transactions 3 | GROUP BY user_id; 4 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/5-group_by/readme.md: -------------------------------------------------------------------------------- 1 | # GROUP BY 2 | 3 | There are times we need to group data based on specific values. 4 | 5 | SQL offers the `GROUP BY` clause which can group rows that have similar values into "summary" rows. It returns one row for each group. The interesting part is that each group can have an aggregate function applied to it that operates only on the grouped data. 6 | 7 | ## Example of GROUP BY 8 | 9 | Imagine that we have a database with songs and albums, and we want to see how many songs are on each album. We can use a query like this: 10 | 11 | ```SQL 12 | SELECT album_id, count(song_id) 13 | FROM songs 14 | GROUP BY album_id; 15 | ``` 16 | 17 | This query retrieves a count of all the songs on each album. One record is returned per album, and they each have their own `count`. 18 | 19 | ## Assignment 20 | 21 | Let's get the balance of *every* user now, all in a single query! Use a combination of the `sum` aggregation and the `GROUP BY` clause to return a single row for each user. 22 | 23 | The row for each user should contain the `user_id` and their `balance` (a sum of their `amount`s) called `balance`. 24 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/6-average/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/7-aggregations/exercises/6-average/code.sql -------------------------------------------------------------------------------- /course/7-aggregations/exercises/6-average/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT avg(age) 2 | FROM users 3 | WHERE country_code = 'US'; 4 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/6-average/readme.md: -------------------------------------------------------------------------------- 1 | # Average 2 | 3 | Just like we may want to find the minimum or maximum values within a dataset, sometimes we need to know the [average](https://en.wikipedia.org/wiki/Arithmetic_mean)! 4 | 5 | SQL offers us the `AVG()` function. Similar to `MAX()`, `AVG()` calculates the average of all non-NULL values. 6 | 7 | ```SQL 8 | select song_name, avg(song_length) 9 | from songs 10 | ``` 11 | 12 | This query returns the average `song_length` in the `songs` table! 13 | 14 | ## Assignment 15 | 16 | Our marketing team is trying to determine the best marketing channels to advertise through but they need more information about our current users. They wish to know the average age of users in the United States. 17 | 18 | Return a single value representing the average age of all `users` where the `country_code` is `US`. 19 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/7-having/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/7-aggregations/exercises/7-having/code.sql -------------------------------------------------------------------------------- /course/7-aggregations/exercises/7-having/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT sender_id, sum(amount) as balance 2 | FROM transactions 3 | WHERE sender_id IS NOT NULL AND note LIKE '%lunch%' 4 | GROUP BY sender_id 5 | HAVING balance > 20 6 | ORDER BY balance asc; 7 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/7-having/readme.md: -------------------------------------------------------------------------------- 1 | # Having 2 | 3 | When we need to filter the results of a `GROUP BY` query even further, we can use the `HAVING` clause. The `HAVING` clause specifies a search condition for a group. 4 | 5 | The `HAVING` clause is similar to the `WHERE` clause, but it operates on groups *after* they've been grouped, rather than rows *before* they've been grouped. 6 | 7 | ```SQL 8 | SELECT album_id, count(id) as count 9 | FROM songs 10 | GROUP BY album_id 11 | HAVING count > 5; 12 | ``` 13 | 14 | This query returns the `album_id` and count of its songs, but only for albums with more than `5` songs. 15 | 16 | ## Assignment 17 | 18 | A new page in the *CashPal* app allows users to see how much money they've spent on a specific kind of transaction, and alerts them if that amount is fairly large. Let's write a query that returns the *total* amount spent by each user on lunch when that balance is greater than `20`. 19 | 20 | Your query should: 21 | 22 | * Return a `sender_id` (the person spending money) and a `balance`. 23 | * The `balance` is the `sum()` of all `amount`s spent. 24 | * Don't return any rows that have a `NULL` `sender_id`. 25 | * Group by `sender_id`. 26 | * The `note` must contain the word `lunch` to be a part of the aggregation. 27 | * The aggregated `balance` must be greater than 20. 28 | * Order the results by the `balance` in ascending order. 29 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/8-having_vs_where/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "In the example, should you use a WHERE or a HAVING clause to filter down to a specific class_id?", 3 | "answers": [ 4 | "WHERE", 5 | "HAVING" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/8-having_vs_where/readme.md: -------------------------------------------------------------------------------- 1 | # HAVING vs WHERE in SQL 2 | 3 | It's fairly common for developers to get confused about the difference between the `HAVING` and the `WHERE` clauses - they're pretty similar after all. 4 | 5 | The difference is fairly simple in actuality: 6 | 7 | * A `WHERE` condition is applied to *all* the data in a query *before* it's grouped by a `GROUP BY` clause. 8 | * A `HAVING` condition is only applied to the *grouped rows* that are returned *after* a `GROUP BY` is applied. 9 | 10 | This means that if you want to filter on the result of an aggregation, you need to use `HAVING`. If you want to filter on a value that's present in the raw data, you should use a simple `WHERE` clause. 11 | 12 | ## Example for the questions 13 | 14 | ```sql 15 | SELECT class_id, count(id) as count 16 | FROM students 17 | WHERE ... 18 | GROUP BY class_id 19 | HAVING ... 20 | ``` 21 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/8a-having_vs_where/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "In the example, should you use a WHERE or a HAVING clause to filter down classes of a particular size?", 3 | "answers": [ 4 | "HAVING", 5 | "WHERE" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/8a-having_vs_where/readme.md: -------------------------------------------------------------------------------- 1 | # HAVING vs WHERE in SQL 2 | 3 | It's fairly common for developers to get confused about the difference between the `HAVING` and the `WHERE` clauses - they're pretty similar after all. 4 | 5 | The difference is fairly simple in actuality: 6 | 7 | * A `WHERE` condition is applied to *all* the data in a query *before* it's grouped by a `GROUP BY` clause. 8 | * A `HAVING` condition is only applied to the *grouped rows* that are returned *after* a `GROUP BY` is applied. 9 | 10 | This means that if you want to filter on the result of an aggregation, you need to use `HAVING`. If you want to filter on a value that's present in the raw data, you should use a simple `WHERE` clause. 11 | 12 | ## Example for the questions 13 | 14 | ```sql 15 | SELECT class_id, count(id) as count 16 | FROM students 17 | WHERE ... 18 | GROUP BY class_id 19 | HAVING ... 20 | ``` 21 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/9-round/code.sql: -------------------------------------------------------------------------------- 1 | SELECT avg(age) 2 | FROM users 3 | WHERE country_code = 'US'; 4 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/9-round/complete.sql: -------------------------------------------------------------------------------- 1 | select round(avg(age), 0) as round_age 2 | from users 3 | where country_code = 'US'; 4 | -------------------------------------------------------------------------------- /course/7-aggregations/exercises/9-round/readme.md: -------------------------------------------------------------------------------- 1 | # Round 2 | 3 | Sometimes we need to [round](https://en.wikipedia.org/wiki/Rounding) some numbers, particularly when working with the results of an aggregation. We can use the `ROUND()` function to get the job done. 4 | 5 | The SQL `round()` function allows you to specify both the value you wish to round and the precision to which you wish to round it: 6 | 7 | ```SQL 8 | round(value, precision) 9 | ``` 10 | 11 | If no precision is given, SQL will round the value to the nearest *whole* value: 12 | 13 | ```SQL 14 | select song_name, round(avg(song_length), 1) 15 | from songs 16 | ``` 17 | 18 | This query returns the average `song_length` from the `songs` table, rounded to a single decimal point. 19 | 20 | ## Assignment 21 | 22 | 1. Fix the query so that it returns a [whole number](https://en.wikipedia.org/wiki/Whole_number). 23 | 2. Rename the result column to `round_age` 24 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/1-subqueries/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/8-subqueries/exercises/1-subqueries/code.sql -------------------------------------------------------------------------------- /course/8-subqueries/exercises/1-subqueries/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * from transactions 2 | WHERE user_id = ( 3 | SELECT id 4 | FROM users 5 | WHERE name = 'David' 6 | ) 7 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/1-subqueries/readme.md: -------------------------------------------------------------------------------- 1 | # Subqueries 2 | 3 | Sometimes a single query is not enough to retrieve the specific records we need. 4 | 5 | It is possible to run a query on the *result set* of another query - a query within a query! This is called "query-ception"... erm... I mean a "subquery". 6 | 7 | Subqueries can be very useful in a number of situations when trying to retrieve specific data that wouldn't be accessible by simply querying a single table. 8 | 9 | ## Retrieving data from multiple tables 10 | 11 | Here is an example of a subquery: 12 | 13 | ```SQL 14 | SELECT id, song_name, artist_id 15 | FROM songs 16 | WHERE artist_id IN ( 17 | SELECT id 18 | FROM artists 19 | WHERE artist_name LIKE 'Rick%' 20 | ); 21 | ``` 22 | 23 | In this hypothetical database, the query above selects all of the `song_id`s, `song_name`s, and `artist_id`s from the `songs` table that are written by artists whose name starts with "Rick". Notice that the subquery allows us to use information from a different table - in this case the `artists` table. 24 | 25 | ## Subquery syntax 26 | 27 | The only syntax unique to a subquery is the parentheses surrounding the nested query. The `IN` operator could be different, for example, we could use the `=` operator if we expect a single value to be returned. 28 | 29 | ## Assignment 30 | 31 | One of CashPal's customer service representatives needs us to pull all the transactions for a specific user. Trouble is, they only know the user's `name`, not their `id`. 32 | 33 | Use a subquery to get all of "David"s transactions. 34 | 35 | ### Transactions Table Schema 36 | 37 | | id | user_id | recipient_id | sender_id | note | amount | was_successful | 38 | | --- | ------- | ------------ | --------- | ---- | ------ | -------------- | 39 | 40 | ### Users Table Schema 41 | 42 | | id | name | age | country_code | username | password | is_admin | 43 | | --- | ---- | --- | ------------ | -------- | -------- | -------- | 44 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/2-subqueries_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "A subquery...", 3 | "answers": [ 4 | "... allows you to query the result set of a nested query", 5 | "... creates a temporary table", 6 | "... is a technique for speeding up your database" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/2-subqueries_quiz/readme.md: -------------------------------------------------------------------------------- 1 | # Subqueries Quiz 2 | 3 | ## Syntax example 4 | 5 | ```SQL 6 | SELECT id, song_name, artist_id 7 | FROM songs 8 | WHERE artist_id IN ( 9 | SELECT id 10 | FROM artists 11 | WHERE artist_name LIKE 'Rick%' 12 | ); 13 | ``` 14 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/2a-subqueries_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "The example will return ____ row(s)", 3 | "answers": [ 4 | "potentially many", 5 | "zero", 6 | "one", 7 | "no more than one" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/2a-subqueries_quiz/readme.md: -------------------------------------------------------------------------------- 1 | # Subqueries Quiz 2 | 3 | ## Syntax example 4 | 5 | ```SQL 6 | SELECT id, song_name, artist_id 7 | FROM songs 8 | WHERE artist_id IN ( 9 | SELECT id 10 | FROM artists 11 | WHERE artist_name LIKE 'Rick%' 12 | ); 13 | ``` 14 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/3-no_tables/code.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/8-subqueries/exercises/3-no_tables/code.sql -------------------------------------------------------------------------------- /course/8-subqueries/exercises/3-no_tables/complete.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM users 2 | WHERE age_in_days > ( 3 | SELECT 365 * 40 4 | ) 5 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/3-no_tables/readme.md: -------------------------------------------------------------------------------- 1 | # No Tables 2 | 3 | When working on a back-end application, this doesn't come up often, but it's important to remember that **SQL is a full programming language**. We usually use it to interact with data stored in tables, but it's quite flexible and powerful. 4 | 5 | For example, you can `SELECT` information that's simply calculated, with no tables necessary. 6 | 7 | ```SQL 8 | SELECT 5 + 10 as sum; 9 | ``` 10 | 11 | ## Assignment 12 | 13 | Finance has found that people who have lived longer than `40` years need to start thinking about retirement. Write a query that returns all the `users` who are more than `40` years old. Unfortunately, this table awkwardly stores age in *days* in the `age_in_days` field. 14 | 15 | Use a subquery to convert `years` -> `days` and filter on that. Assume every year has `365` days. 16 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/3-no_tables/up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age_in_days INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | INSERT INTO users(name, age_in_days, country_code, username, password, is_admin) 12 | VALUES ('David', 14560, 'US', 'DavidDev', 'insertPractice', false); 13 | 14 | INSERT INTO users(name, age_in_days, country_code, username, password, is_admin) 15 | VALUES ('Samantha', 15560, 'BR', 'Sammy93', 'addingRecords!', false); 16 | 17 | INSERT INTO users(name, age_in_days, country_code, username, password, is_admin) 18 | VALUES ('John', 10560, 'CA', 'Jjdev21', 'welovebootdev', false); 19 | 20 | INSERT INTO users(name, age_in_days, country_code, username, password, is_admin) 21 | VALUES ('Ram', 4560, 'IN', 'Ram11c', 'thisSQLcourserocks', false); 22 | 23 | INSERT INTO users(name, age_in_days, country_code, username, password, is_admin) 24 | VALUES ('Hunter', 20560, 'US', 'Hdev92', 'backendDev', false); 25 | 26 | INSERT INTO users(name, age_in_days, country_code, username, password, is_admin) 27 | VALUES ('Allan', 560, 'US', 'Alires', 'iLoveB00tdev', true); 28 | 29 | INSERT INTO users(name, age_in_days, country_code, username, password, is_admin) 30 | VALUES ('Lance', 17560, 'US', 'LanChr', 'b00tdevisbest', false); 31 | 32 | INSERT INTO users(name, age_in_days, country_code, username, password, is_admin) 33 | VALUES ('Tiffany', 18560, 'US', 'Tifferoon', 'autoincrement', true); 34 | 35 | INSERT INTO users(name, age_in_days, country_code, username, password, is_admin) 36 | VALUES ('Lane', 9560, 'US', 'wagslane', 'update_me', false); 37 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/4-no_tables_quiz/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "SQL can only operate on data stored in tables", 3 | "answers": [ 4 | "False", 5 | "True" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/8-subqueries/exercises/4-no_tables_quiz/readme.md: -------------------------------------------------------------------------------- 1 | # Quiz 2 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/1-one_to_one/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which is an example of a one-to-one relationship?", 3 | "answers": [ 4 | "A transaction's 'note'", 5 | "A user's transactions", 6 | "A father's children", 7 | "A university's professors" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/1-one_to_one/readme.md: -------------------------------------------------------------------------------- 1 | # Table Relationships 2 | 3 | Relational databases are powerful because of the relationships between the tables. These relationships help us to keep our databases clean and efficient. A relationship between tables assumes that one of these tables has a `foreign key` that references the `primary key` of another table. 4 | 5 | @[youtube](https://www.youtube.com/watch?v=WJTdg1AsSz0) 6 | 7 | ## Types of Relationships 8 | 9 | There are 3 primary types of relationships in a relational database: 10 | 11 | 1. One-to-one 12 | 2. One-to-many 13 | 3. Many-to-many 14 | 15 | ![relationships](https://i.imgur.com/u4i6XdL.png) 16 | 17 | # One-to-one 18 | 19 | A `one-to-one` relationship most often manifests as a field or set of fields on a row in a table. For example, a `user` will have exactly one `password`. 20 | 21 | Settings fields might be another example of a one-to-one relationship. A user will have exactly one `email_preference` and exactly one `birthday`. 22 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/10-normalization_review/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which should you optimize for first?", 3 | "answers": [ 4 | "Reducing duplicate data", 5 | "Speed" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/10-normalization_review/readme.md: -------------------------------------------------------------------------------- 1 | # Normalization Review 2 | 3 | In my opinion, the *exact* definitions of 1st, 2nd, 3rd and Boyce-Codd normal forms simply are *not all that important* in your work as a back-end developer. 4 | 5 | However, what *is important* is to understand the basic principles of data integrity and data redundancy that the normal forms teach us. Let's go over some rules of thumb that you should commit to memory - they'll serve you well when you design databases and even just in coding interviews. 6 | 7 | ## Rules of thumb for database design 8 | 9 | 1. Every table should always have a unique identifier (primary key) 10 | 2. 90% of the time, that unique identifier will be a single column named `id` 11 | 3. Avoid duplicate data 12 | 4. Avoid storing data that is completely dependent on other data. Instead, compute it on the fly when you need it. 13 | 5. Keep your schema as simple as you can. Optimize for a *normalized* database first. Only denormalize for speed's sake when you start to run into performance problems. 14 | 15 | We'll talk more about speed optimization in a later chapter. 16 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/10a-normalization_review/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "When you don't need a composite key, what should the name of your primary key's column be?", 3 | "answers": [ 4 | "id", 5 | "identifier", 6 | "key", 7 | "skeleton_key" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/10a-normalization_review/readme.md: -------------------------------------------------------------------------------- 1 | # Normalization Review 2 | 3 | In my opinion, the *exact* definitions of 1st, 2nd, 3rd and Boyce-Codd normal forms simply are *not all that important* in your work as a back-end developer. 4 | 5 | However, what *is important* is to understand the basic principles of data integrity and data redundancy that the normal forms teach us. Let's go over some rules of thumb that you should commit to memory - they'll serve you well when you design databases and even just in coding interviews. 6 | 7 | ## Rules of thumb for database design 8 | 9 | 1. Every table should always have a unique identifier (primary key) 10 | 2. 90% of the time, that unique identifier will be a single column named `id` 11 | 3. Avoid duplicate data 12 | 4. Avoid storing data that is completely dependent on other data. Instead, compute it on the fly when you need it. 13 | 5. Keep your schema as simple as you can. Optimize for a *normalized* database first. Only denormalize for speed's sake when you start to run into performance problems. 14 | 15 | We'll talk more about speed optimization in a later chapter. 16 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/10b-normalization_review/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which is more important for your career in back-end development?", 3 | "answers": [ 4 | "Internalizing simple rules-of-thumb regarding database normalization", 5 | "Memorizing the exact definitions of 1NF, 2NF, 3NF and BCNF" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/10b-normalization_review/readme.md: -------------------------------------------------------------------------------- 1 | # Normalization Review 2 | 3 | In my opinion, the *exact* definitions of 1st, 2nd, 3rd and Boyce-Codd normal forms simply are *not all that important* in your work as a back-end developer. 4 | 5 | However, what *is important* is to understand the basic principles of data integrity and data redundancy that the normal forms teach us. Let's go over some rules of thumb that you should commit to memory - they'll serve you well when you design databases and even just in coding interviews. 6 | 7 | ## Rules of thumb for database design 8 | 9 | 1. Every table should always have a unique identifier (primary key) 10 | 2. 90% of the time, that unique identifier will be a single column named `id` 11 | 3. Avoid duplicate data 12 | 4. Avoid storing data that is completely dependent on other data. Instead, compute it on the fly when you need it. 13 | 5. Keep your schema as simple as you can. Optimize for a *normalized* database first. Only denormalize for speed's sake when you start to run into performance problems. 14 | 15 | We'll talk more about speed optimization in a later chapter. 16 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/1a-one_to_one/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "How would you model the relationship between a class and its name?", 3 | "answers": [ 4 | "One to one", 5 | "One to many", 6 | "Many to many" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/1a-one_to_one/readme.md: -------------------------------------------------------------------------------- 1 | # Table Relationships 2 | 3 | Relational databases are powerful because of the relationships between the tables. These relationships help us to keep our databases clean and efficient. A relationship between tables assumes that one of these tables has a `foreign key` that references the `primary key` of another table. 4 | 5 | @[youtube](https://www.youtube.com/watch?v=WJTdg1AsSz0) 6 | 7 | ## Types of Relationships 8 | 9 | There are 3 primary types of relationships in a relational database: 10 | 11 | 1. One-to-one 12 | 2. One-to-many 13 | 3. Many-to-many 14 | 15 | ![relationships](https://i.imgur.com/u4i6XdL.png) 16 | 17 | # One-to-one 18 | 19 | A `one-to-one` relationship most often manifests as a field or set of fields on a row in a table. For example, a `user` will have exactly one `password`. 20 | 21 | Settings fields might be another example of a one-to-one relationship. A user will have exactly one `email_preference` and exactly one `birthday`. 22 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/2-one_to_many/code.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | country_code TEXT NOT NULL, 6 | username TEXT UNIQUE, 7 | password TEXT NOT NULL, 8 | is_admin BOOLEAN 9 | ); 10 | 11 | -- Don't touch below this line -- 12 | 13 | INSERT INTO users(name, age, username, password, is_admin) 14 | VALUES ('David', 34, 'david.lang', 'secure1234', false); 15 | 16 | INSERT INTO users(name, age, username, password, is_admin) 17 | VALUES ('Sam', 12, 'sam-show', 'nasjds134', false); 18 | 19 | INSERT INTO users(name, age, username, password, is_admin) 20 | VALUES ('Lane', 19, 'wagslane', '2jk3bAkm', false); 21 | 22 | INSERT INTO users(name, age, username, password, is_admin) 23 | VALUES ('Allan', 27, 'allan.jules', '243nldn', false); 24 | 25 | INSERT INTO countries(country_code, name, user_id) 26 | VALUES ('US', 'United States', 1); 27 | 28 | INSERT INTO countries(country_code, name, user_id) 29 | VALUES ('CA', 'Canada', 1); 30 | 31 | INSERT INTO countries(country_code, name, user_id) 32 | VALUES ('IN', 'India', 2); 33 | 34 | INSERT INTO countries(country_code, name, user_id) 35 | VALUES ('JP', 'Japan', 3); 36 | 37 | INSERT INTO countries(country_code, name, user_id) 38 | VALUES ('BR', 'Brazil', 4); 39 | 40 | SELECT * FROM countries 41 | WHERE user_id IN ( 42 | SELECT id from users 43 | ) 44 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/2-one_to_many/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | username TEXT UNIQUE, 6 | password TEXT NOT NULL, 7 | is_admin BOOLEAN 8 | ); 9 | 10 | CREATE TABLE countries ( 11 | id INTEGER PRIMARY KEY, 12 | country_code TEXT, 13 | name TEXT, 14 | user_id INTEGER, 15 | FOREIGN KEY (user_id) 16 | REFERENCES users (id) 17 | ); 18 | 19 | -- Don't touch below this line -- 20 | 21 | INSERT INTO users(name, age, username, password, is_admin) 22 | VALUES ('David', 34, 'david.lang', 'secure1234', false); 23 | 24 | INSERT INTO users(name, age, username, password, is_admin) 25 | VALUES ('Sam', 12, 'sam-show', 'nasjds134', false); 26 | 27 | INSERT INTO users(name, age, username, password, is_admin) 28 | VALUES ('Lane', 19, 'wagslane', '2jk3bAkm', false); 29 | 30 | INSERT INTO users(name, age, username, password, is_admin) 31 | VALUES ('Allan', 27, 'allan.jules', '243nldn', false); 32 | 33 | INSERT INTO countries(country_code, name, user_id) 34 | VALUES ('US', 'United States', 1); 35 | 36 | INSERT INTO countries(country_code, name, user_id) 37 | VALUES ('CA', 'Canada', 1); 38 | 39 | INSERT INTO countries(country_code, name, user_id) 40 | VALUES ('IN', 'India', 2); 41 | 42 | INSERT INTO countries(country_code, name, user_id) 43 | VALUES ('JP', 'Japan', 3); 44 | 45 | INSERT INTO countries(country_code, name, user_id) 46 | VALUES ('BR', 'Brazil', 4); 47 | 48 | SELECT * FROM countries 49 | WHERE user_id IN ( 50 | SELECT id from users 51 | ) 52 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/2-one_to_many/readme.md: -------------------------------------------------------------------------------- 1 | # One to many 2 | 3 | When talking about the relationships between *tables*, a one-to-many relationship is probably the most commonly used relationship. 4 | 5 | A one-to-many relationship occurs when a single record in one table is related to potentially many records in another table. 6 | 7 | Note that the one->many relation only goes *one way*, a record in the second table can *not* be related to multiple records in the first table! 8 | 9 | ## Examples of one-to-many relationships 10 | 11 | * A `customers` table and a `orders` table. Each customer has `0`, `1`, or many orders that they've placed. 12 | * A `users` table and a `transactions` table. Each `user` has `0`, `1`, or many transactions that taken part in. 13 | 14 | ## Assignment 15 | 16 | It turns out that when we originally designed the CashPal database schema we assumed that users would only have a *single* country they lived in. With digital nomads becoming a thing, it turns out many users have dual citizenship. 17 | 18 | Instead of a single `users` table where each user has a single `country_code`, do the following: 19 | 20 | * Remove the `country_code` field from the `users` table 21 | * Create a new table called `countries` with 4 fields: 22 | * `id`: an integer 23 | * `country_code`: a string 24 | * `name`: a string 25 | * `user_id`: an integer foreign key to the `users` table's `id` field 26 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/2-one_to_many/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/9-normalization/exercises/2-one_to_many/up.sql -------------------------------------------------------------------------------- /course/9-normalization/exercises/3-many_to_many/code.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | username TEXT UNIQUE, 6 | password TEXT NOT NULL, 7 | is_admin BOOLEAN 8 | ); 9 | 10 | CREATE TABLE countries ( 11 | id INTEGER PRIMARY KEY, 12 | country_code TEXT, 13 | name TEXT, 14 | user_id INTEGER, 15 | FOREIGN KEY (country_code) 16 | REFERENCES users (id) 17 | ); 18 | 19 | -- Don't touch below this line -- 20 | 21 | INSERT INTO users(name, age, username, password, is_admin) 22 | VALUES ('David', 34, 'david.lang', 'secure1234', false); 23 | 24 | INSERT INTO users(name, age, username, password, is_admin) 25 | VALUES ('Sam', 12, 'sam-show', 'nasjds134', false); 26 | 27 | INSERT INTO users(name, age, username, password, is_admin) 28 | VALUES ('Lane', 19, 'wagslane', '2jk3bAkm', false); 29 | 30 | INSERT INTO users(name, age, username, password, is_admin) 31 | VALUES ('Allan', 27, 'allan.jules', '243nldn', false); 32 | 33 | INSERT INTO countries(country_code, name) 34 | VALUES ('US', 'United States'); 35 | 36 | INSERT INTO countries(country_code, name) 37 | VALUES ('CA', 'Canada'); 38 | 39 | INSERT INTO countries(country_code, name) 40 | VALUES ('IN', 'India'); 41 | 42 | INSERT INTO countries(country_code, name) 43 | VALUES ('JP', 'Japan'); 44 | 45 | INSERT INTO countries(country_code, name) 46 | VALUES ('BR', 'Brazil'); 47 | 48 | INSERT INTO users_countries(country_id, user_id) 49 | VALUES (1, 1); 50 | 51 | INSERT INTO users_countries(country_id, user_id) 52 | VALUES (1, 2); 53 | 54 | INSERT INTO users_countries(country_id, user_id) 55 | VALUES (2, 2); 56 | 57 | INSERT INTO users_countries(country_id, user_id) 58 | VALUES (2, 3); 59 | 60 | INSERT INTO users_countries(country_id, user_id) 61 | VALUES (3, 3); 62 | 63 | INSERT INTO users_countries(country_id, user_id) 64 | VALUES (4, 3); 65 | 66 | SELECT * FROM countries 67 | WHERE id IN ( 68 | SELECT country_id from users_countries 69 | ) 70 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/3-many_to_many/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL, 5 | username TEXT UNIQUE, 6 | password TEXT NOT NULL, 7 | is_admin BOOLEAN 8 | ); 9 | 10 | CREATE TABLE users_countries ( 11 | country_id INTEGER, 12 | user_id INTEGER, 13 | UNIQUE(country_id, user_id) 14 | ); 15 | 16 | CREATE TABLE countries ( 17 | id INTEGER PRIMARY KEY, 18 | country_code TEXT, 19 | name TEXT 20 | ); 21 | 22 | -- Don't touch below this line -- 23 | 24 | INSERT INTO users(name, age, username, password, is_admin) 25 | VALUES ('David', 34, 'david.lang', 'secure1234', false); 26 | 27 | INSERT INTO users(name, age, username, password, is_admin) 28 | VALUES ('Sam', 12, 'sam-show', 'nasjds134', false); 29 | 30 | INSERT INTO users(name, age, username, password, is_admin) 31 | VALUES ('Lane', 19, 'wagslane', '2jk3bAkm', false); 32 | 33 | INSERT INTO users(name, age, username, password, is_admin) 34 | VALUES ('Allan', 27, 'allan.jules', '243nldn', false); 35 | 36 | INSERT INTO countries(country_code, name) 37 | VALUES ('US', 'United States'); 38 | 39 | INSERT INTO countries(country_code, name) 40 | VALUES ('CA', 'Canada'); 41 | 42 | INSERT INTO countries(country_code, name) 43 | VALUES ('IN', 'India'); 44 | 45 | INSERT INTO countries(country_code, name) 46 | VALUES ('JP', 'Japan'); 47 | 48 | INSERT INTO countries(country_code, name) 49 | VALUES ('BR', 'Brazil'); 50 | 51 | INSERT INTO users_countries(country_id, user_id) 52 | VALUES (1, 1); 53 | 54 | INSERT INTO users_countries(country_id, user_id) 55 | VALUES (1, 2); 56 | 57 | INSERT INTO users_countries(country_id, user_id) 58 | VALUES (2, 2); 59 | 60 | INSERT INTO users_countries(country_id, user_id) 61 | VALUES (2, 3); 62 | 63 | INSERT INTO users_countries(country_id, user_id) 64 | VALUES (3, 3); 65 | 66 | INSERT INTO users_countries(country_id, user_id) 67 | VALUES (4, 3); 68 | 69 | SELECT * FROM countries 70 | WHERE id IN ( 71 | SELECT country_id from users_countries 72 | ) 73 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/3-many_to_many/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/9-normalization/exercises/3-many_to_many/up.sql -------------------------------------------------------------------------------- /course/9-normalization/exercises/4-normalization/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "To improve data integrity, data should generally be stored in a ____ form", 3 | "answers": [ 4 | "Raw", 5 | "Pre-calculated" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/4-normalization/readme.md: -------------------------------------------------------------------------------- 1 | # Database normalization 2 | 3 | Database normalization is a method for structuring your database schema in a way that helps: 4 | 5 | * Improve data integrity 6 | * Reduce data redundancy 7 | 8 | @[youtube](https://www.youtube.com/watch?v=Tkekmm1XEMQ) 9 | 10 | ## What is data integrity? 11 | 12 | "Data integrity" refers to the accuracy and consistency of data. For example, if a user's *age* is stored in a database, rather than their *birthday*, that data becomes incorrect automatically with the passage of time. 13 | 14 | It would be better to *store* a birthday and *calculate* the age as needed. 15 | 16 | ## What is data redundancy? 17 | 18 | "Data redundancy" occurs when the same piece of data is stored in multiple places. For example: saving the same file multiple times to different hard drives. 19 | 20 | Data redundancy can be problematic, especially when data in one place is changed such that the data is no longer consistent across all copies of that data. 21 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/4a-normalization/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Pick the best example of data redundancy", 3 | "answers": [ 4 | "A users address is stored in two different tables", 5 | "Each table has an id field as its primary key", 6 | "A country table and a users table each contain a field called name", 7 | "Two tables both contain fields that store a boolean value" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/4a-normalization/readme.md: -------------------------------------------------------------------------------- 1 | # Database normalization 2 | 3 | Database normalization is a method for structuring your database schema in a way that helps: 4 | 5 | * Improve data integrity 6 | * Reduce data redundancy 7 | 8 | @[youtube](https://www.youtube.com/watch?v=Tkekmm1XEMQ) 9 | 10 | ## What is data integrity? 11 | 12 | "Data integrity" refers to the accuracy and consistency of data. For example, if a user's *age* is stored in a database, rather than their *birthday*, that data becomes incorrect automatically with the passage of time. 13 | 14 | It would be better to *store* a birthday and *calculate* the age as needed. 15 | 16 | ## What is data redundancy? 17 | 18 | "Data redundancy" occurs when the same piece of data is stored in multiple places. For example: saving the same file multiple times to different hard drives. 19 | 20 | Data redundancy can be problematic, especially when data in one place is changed such that the data is no longer consistent across all copies of that data. 21 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/5-normal_forms/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which form has the most duplicate data?", 3 | "answers": [ 4 | "1NF", 5 | "2NF", 6 | "3NF", 7 | "BCNF" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/5-normal_forms/readme.md: -------------------------------------------------------------------------------- 1 | # Normal Forms 2 | 3 | The creator of "database normalization", [Edgar F. Codd](https://en.wikipedia.org/wiki/Edgar_F._Codd) described different "normal forms" a database can adhere to. We'll talk about the most common ones. 4 | 5 | * First normal form (1NF) 6 | * Second normal form (2NF) 7 | * Third normal form (3NF) 8 | * Boyce-Codd normal form (BCNF) 9 | 10 | ![normal forms](https://i.imgur.com/CpDOeej.png) 11 | 12 | In short, 1st normal form is the *least* "normalized" form, and Boyce-Codd is the *most* "normalized" form. 13 | 14 | The more normalized a database, the better its data integrity, and the less duplicate data you'll have. 15 | 16 | ## In the context of normal forms, "primary key" means something a bit different 17 | 18 | In the context of database normalization, we're going to use the term "primary key" slightly differently. When we're talking about SQLite, a "primary key" is a single column that uniquely identifies a row. 19 | 20 | When we're talking more generally about data normalization, the term "primary key" means the *collection* of columns that uniquely identify a row. That *can be* a single column, but it can actually be any number of columns. A primary key is the minimum number of columns needed to uniquely identify a row in a table. 21 | 22 | If you think back to the many-to-many joining table `product_suppliers`, that table's "primary key" was actually a *combination* of the 2 ids, `product_id` and `supplier_id`: 23 | 24 | ```SQL 25 | CREATE TABLE product_suppliers ( 26 | product_id INTEGER, 27 | supplier_id INTEGER, 28 | UNIQUE(product_id, supplier_id) 29 | ); 30 | ``` 31 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/5a-normal_forms/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "Which form encourages the most accurate and up-to-date information?", 3 | "answers": [ 4 | "BCNF", 5 | "1NF", 6 | "2NF", 7 | "3NF" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/5a-normal_forms/readme.md: -------------------------------------------------------------------------------- 1 | # Normal Forms 2 | 3 | The creator of "database normalization", [Edgar F. Codd](https://en.wikipedia.org/wiki/Edgar_F._Codd) described different "normal forms" a database can adhere to. We'll talk about the most common ones. 4 | 5 | * First normal form (1NF) 6 | * Second normal form (2NF) 7 | * Third normal form (3NF) 8 | * Boyce-Codd normal form (BCNF) 9 | 10 | ![normal forms](https://i.imgur.com/CpDOeej.png) 11 | 12 | In short, 1st normal form is the *least* "normalized" form, and Boyce-Codd is the *most* "normalized" form. 13 | 14 | The more normalized a database, the better its data integrity, and the less duplicate data you'll have. 15 | 16 | ## In the context of normal forms, "primary key" means something a bit different 17 | 18 | In the context of database normalization, we're going to use the term "primary key" slightly differently. When we're talking about SQLite, a "primary key" is a single column that uniquely identifies a row. 19 | 20 | When we're talking more generally about data normalization, the term "primary key" means the *collection* of columns that uniquely identify a row. That *can be* a single column, but it can actually be any number of columns. A primary key is the minimum number of columns needed to uniquely identify a row in a table. 21 | 22 | If you think back to the many-to-many joining table `product_suppliers`, that table's "primary key" was actually a *combination* of the 2 ids, `product_id` and `supplier_id`: 23 | 24 | ```SQL 25 | CREATE TABLE product_suppliers ( 26 | product_id INTEGER, 27 | supplier_id INTEGER, 28 | UNIQUE(product_id, supplier_id) 29 | ); 30 | ``` 31 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/5b-normal_forms/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "In the context of normalization, a primary key is made up of ____ table columns", 3 | "answers": [ 4 | "1-many", 5 | "1-2", 6 | "1", 7 | "0-1" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/5b-normal_forms/readme.md: -------------------------------------------------------------------------------- 1 | # Normal Forms 2 | 3 | The creator of "database normalization", [Edgar F. Codd](https://en.wikipedia.org/wiki/Edgar_F._Codd) described different "normal forms" a database can adhere to. We'll talk about the most common ones. 4 | 5 | * First normal form (1NF) 6 | * Second normal form (2NF) 7 | * Third normal form (3NF) 8 | * Boyce-Codd normal form (BCNF) 9 | 10 | ![normal forms](https://i.imgur.com/CpDOeej.png) 11 | 12 | In short, 1st normal form is the *least* "normalized" form, and Boyce-Codd is the *most* "normalized" form. 13 | 14 | The more normalized a database, the better its data integrity, and the less duplicate data you'll have. 15 | 16 | ## In the context of normal forms, "primary key" means something a bit different 17 | 18 | In the context of database normalization, we're going to use the term "primary key" slightly differently. When we're talking about SQLite, a "primary key" is a single column that uniquely identifies a row. 19 | 20 | When we're talking more generally about data normalization, the term "primary key" means the *collection* of columns that uniquely identify a row. That *can be* a single column, but it can actually be any number of columns. A primary key is the minimum number of columns needed to uniquely identify a row in a table. 21 | 22 | If you think back to the many-to-many joining table `product_suppliers`, that table's "primary key" was actually a *combination* of the 2 ids, `product_id` and `supplier_id`: 23 | 24 | ```SQL 25 | CREATE TABLE product_suppliers ( 26 | product_id INTEGER, 27 | supplier_id INTEGER, 28 | UNIQUE(product_id, supplier_id) 29 | ); 30 | ``` 31 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/6-first_nf/code.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE companies ( 2 | name TEXT NOT NULL, 3 | num_employees INTEGER NOT NULL 4 | ); 5 | 6 | -- Don't touch below this line -- 7 | 8 | pragma table_info('companies'); 9 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/6-first_nf/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE companies ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | num_employees INTEGER NOT NULL 5 | ); 6 | 7 | -- Don't touch below this line -- 8 | 9 | pragma table_info('companies'); 10 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/6-first_nf/readme.md: -------------------------------------------------------------------------------- 1 | # 1st Normal Form (1NF) 2 | 3 | To be compliant with [first normal form](https://en.wikipedia.org/wiki/First_normal_form), a database table simply needs to follow 2 rules: 4 | 5 | * It must have a unique primary key. 6 | * A cell can't have a nested table as its value (depending on the database you're using, this may not even be *possible*) 7 | 8 | ## Example of NOT 1st normal form 9 | 10 | | name | age | email | 11 | | ----- | --- | -------------- | 12 | | Lane | 27 | lane@boot.dev | 13 | | Lane | 27 | lane@boot.dev | 14 | | Allan | 27 | allan@boot.dev | 15 | 16 | This table does *not* adhere to 1NF. It has two identical rows, so there isn't a unique primary key for each row. 17 | 18 | ## Example of 1st normal form 19 | 20 | The simplest way (but not the only way) to get into first normal form is to add a unique `id` column. 21 | 22 | | id | name | age | email | 23 | | --- | ----- | --- | -------------- | 24 | | 1 | Lane | 27 | lane@boot.dev | 25 | | 2 | Lane | 27 | lane@boot.dev | 26 | | 3 | Allan | 27 | allan@boot.dev | 27 | 28 | It's worth noting that if you create a "primary key" by ensuring that two columns are always "unique together" that works too. 29 | 30 | ## You should *almost* never design a table that doesn't adhere to 1NF 31 | 32 | First normal form is simply *a good idea*. I've *never* built a database schema where each table isn't *at least* in first normal form. 33 | 34 | ## Assignment 35 | 36 | We hired an intern at CashPal and her first task was to design a new "companies" table. This table will store our business client's data. Unfortunately, she has committed the unforgivable sin - there's no primary key on this table! We could have entire duplicate rows! 37 | 38 | Add an `id` field. It should be an integer and have a `PRIMARY KEY` constraint on it. When you're done, the `companies` table will be in first normal form. 39 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/6-first_nf/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/9-normalization/exercises/6-first_nf/up.sql -------------------------------------------------------------------------------- /course/9-normalization/exercises/7-second_nf/code.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL 5 | ); 6 | 7 | CREATE TABLE companies ( 8 | id INTEGER PRIMARY KEY, 9 | name TEXT NOT NULL, 10 | num_employees INTEGER NOT NULL 11 | ); 12 | 13 | CREATE TABLE users_companies ( 14 | user_id INTEGER, 15 | company_id INTEGER, 16 | company_revenue INTEGER, 17 | UNIQUE(user_id, company_id) 18 | ); 19 | 20 | -- Don't touch below this line -- 21 | 22 | pragma table_info('companies'); 23 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/7-second_nf/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | age INTEGER NOT NULL 5 | ); 6 | 7 | CREATE TABLE companies ( 8 | id INTEGER PRIMARY KEY, 9 | name TEXT NOT NULL, 10 | num_employees INTEGER NOT NULL, 11 | company_revenue INTEGER 12 | ); 13 | 14 | CREATE TABLE users_companies ( 15 | user_id INTEGER, 16 | company_id INTEGER, 17 | UNIQUE(user_id, company_id) 18 | ); 19 | 20 | -- Don't touch below this line -- 21 | 22 | pragma table_info('companies'); 23 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/7-second_nf/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/9-normalization/exercises/7-second_nf/up.sql -------------------------------------------------------------------------------- /course/9-normalization/exercises/8-third_nf/code.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE companies ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | num_employees INTEGER NOT NULL, 5 | size TEXT 6 | ); 7 | 8 | -- Don't touch between these comments -- 9 | 10 | INSERT INTO companies(name, num_employees) 11 | VALUES ("Pfizer", 10000); 12 | INSERT INTO companies(name, num_employees) 13 | VALUES ("Johnny's Diner", 4); 14 | INSERT INTO companies(name, num_employees) 15 | VALUES ("Joe's Cafe", 12); 16 | INSERT INTO companies(name, num_employees) 17 | VALUES ("Walmart", 1000); 18 | 19 | -- Don't touch between these comments -- 20 | 21 | SELECT * 22 | FROM companies; 23 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/8-third_nf/complete.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE companies ( 2 | id INTEGER PRIMARY KEY, 3 | name TEXT NOT NULL, 4 | num_employees INTEGER NOT NULL 5 | ); 6 | 7 | -- Don't touch between these comments -- 8 | 9 | INSERT INTO companies(name, num_employees) 10 | VALUES ("Pfizer", 10000); 11 | INSERT INTO companies(name, num_employees) 12 | VALUES ("Johnny's Diner", 4); 13 | INSERT INTO companies(name, num_employees) 14 | VALUES ("Joe's Cafe", 12); 15 | INSERT INTO companies(name, num_employees) 16 | VALUES ("Walmart", 1000); 17 | 18 | -- Don't touch between these comments -- 19 | 20 | SELECT *, IIF(num_employees > 100, "large", "small") as size 21 | FROM companies; 22 | -------------------------------------------------------------------------------- /course/9-normalization/exercises/8-third_nf/up.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootdotdev/fcc-learn-sql-assets/bae106ccf2777260d76d36fde8f6a642197b21a3/course/9-normalization/exercises/8-third_nf/up.sql -------------------------------------------------------------------------------- /course/9-normalization/exercises/9-boyce_codd_nf/multiple_choice.json: -------------------------------------------------------------------------------- 1 | { 2 | "question": "When can a table be in 3NF but not BCNF?", 3 | "answers": [ 4 | "It has multiple possible primary key combinations, and one of the columns in a possible primary key is dependent on a column outside of that primary key", 5 | "It has multiple possible primary keys", 6 | "It has a primary key that depends on another column that's not a primary key", 7 | "When Raymond F Boyce and Edgar F Codd decree it so from on-high" 8 | ] 9 | } 10 | --------------------------------------------------------------------------------