Skip to content

Commit 031244b

Browse files
authored
Merge pull request #3268 from root-0101/sql
Add SQL docs
2 parents ac0424f + 495f787 commit 031244b

10 files changed

+2485
-0
lines changed

docs/SQL/01-intro-to-dbms-sql.md

Lines changed: 215 additions & 0 deletions
Large diffs are not rendered by default.

docs/SQL/02-crud-operations.md

Lines changed: 389 additions & 0 deletions
Large diffs are not rendered by default.

docs/SQL/03-crud2.md

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
# Crud pt-2
2+
3+
### Agenda
4+
- Delete
5+
- Delete vs truncate vs drop
6+
- Limit
7+
- Count
8+
- Order By
9+
- Join
10+
11+
12+
### Delete
13+
14+
```sql
15+
DELETE FROM table_name WHERE conditions;
16+
```
17+
18+
Example:
19+
20+
```sql
21+
DELETE FROM film WHERE id = 1;
22+
```
23+
24+
The above query will delete the row with `id` 1 from the `film` table.
25+
26+
Beware, If you don't specify a where clause, then all the rows from the table will be deleted. Example:
27+
28+
```sql
29+
DELETE FROM film;
30+
```
31+
32+
Let's talk about how delete works as well in terms of code.
33+
34+
```python
35+
for each row in film:
36+
if row.matches(conditions in where clause)
37+
delete row
38+
```
39+
40+
There is a minor advance thing about DELETE which we shall talk about along with Joins in the next class. So, don't worry about it for now.
41+
42+
### Delete vs Truncate vs Drop
43+
44+
There are two more commands which are used to delete rows from a table. They are `TRUNCATE` and `DROP`. Let's discuss them one by one.
45+
46+
#### Truncate
47+
48+
The command looks as follows:
49+
50+
```sql
51+
TRUNCATE film;
52+
```
53+
54+
The above query will delete all the rows from the `film` table. TRUNCATE command internally works by removing the complete table and then recreating it. So, it is much faster than DELETE. But it has a disadvantage. It cannot be rolled back. We will learn more about rollbacks in the class on Transactions (In short, rollbacks can only happen for incomplete transactions - not committed yet - to be discussed in future classes). But at a high level, this is because as the complete table is deleted as an intermediate step, no log is maintained as to what all rows were deleted, and thus is not easy to revert. So, if you run a TRUNCATE query, then you cannot undo it.
55+
56+
>Note: It also resets the primary key ID. For example, if the highest ID in the table before truncating was 10, then the next row inserted after truncating will have an ID of 1.
57+
58+
#### Drop
59+
60+
The command looks as follows:
61+
62+
Example:
63+
64+
```sql
65+
DROP TABLE film;
66+
```
67+
68+
The above query will delete the `film` table. The difference between `DELETE` and `DROP` is that `DELETE` is used to delete rows from a table and `DROP` is used to delete the entire table. So, if you run a `DROP` query, then the entire table will be deleted. All the rows and the table structure will be deleted. So, be careful while running a `DROP` query. Nothing will be left of the table after running a `DROP` query. You will have to recreate the table from scratch.
69+
70+
Note that,
71+
DELETE:
72+
1. Removes specified rows one-by-one from table (may delete all rows if no condition is present in query but keeps table structure intact).
73+
2. It is slower than TRUNCATE.
74+
3. Doesn't reset the key.
75+
4. It can be rolled back.
76+
77+
TRUNCATE:
78+
1. Removes the complete table and then recreats it.
79+
2. Faster than DELETE.
80+
3. Resets the key.
81+
4. It can not be rolled back because the complete table is deleted as an intermediate step.
82+
83+
DROP:
84+
1. Removes complete table and the table structre as well.
85+
2. It can not be rolled back.
86+
87+
Rollback to be discussed in transactions class. Note that there is no undo in SQL queries once the query is completely committed.
88+
89+
90+
### LIKE Operator
91+
92+
LIKE operator is one of the most important and frequently used operator in SQL. Whenever there is a column storing strings, there comes a requirement to do some kind of pattern matching. Example, assume Scaler's database where we have a `batches` table with a column called `name`. Let's say we want to get the list of `Academy` batches and the rule is that an Academy batch shall have `Academy` somewhere within the name. How do we find those? We can use the `LIKE` operator for this purpose. Example:
93+
94+
```sql
95+
SELECT * FROM batches WHERE name LIKE '%Academy%';
96+
```
97+
98+
Similarly, let's say in our Sakila database, we want to get all the films which have `LOVE` in their title. We can use the `LIKE` operator. Example:
99+
100+
```sql
101+
SELECT * FROM film WHERE title LIKE '%LOVE%';
102+
```
103+
104+
Let's talk about how the `LIKE` operator works. The `LIKE` operator works with the help of 2 wildcards in our queries, `%` and `_`. The `%` wildcard matches any number of characters (>= 0 occurrences of any set of characters). The `_` wildcard matches exactly one character (any character). Example:
105+
106+
1. LIKE 'cat%' will match "cat", "caterpillar", "category", etc. but not "wildcat" or "dog".
107+
2. LIKE '%cat' will match "cat", "wildcat", "domesticcat", etc. but not "cattle" or "dog".
108+
3. LIKE '%cat%' will match "cat", "wildcat", "cattle", "domesticcat", "caterpillar", "category", etc. but not "dog" or "bat".
109+
4. LIKE '_at' will match "cat", "bat", "hat", etc. but not "wildcat" or "domesticcat".
110+
5. LIKE 'c_t' will match "cat", "cot", "cut", etc. but not "chat" or "domesticcat".
111+
6. LIKE 'c%t' will match "cat", "chart", "connect", "cult", etc. but not "wildcat", "domesticcat", "caterpillar", "category".
112+
113+
114+
### COUNT
115+
116+
Count function takes the values from a particular column and returns the number of values in that set. Umm, but don't you think it will be exactly same as the number of rows in the table? Nope. Not true. Aggregate functions only take not null values into account. So, if there are any null values in the column, they will not be counted.
117+
118+
Example: Let's take a students table with data like follows:
119+
120+
| id | name | age | batch_id |
121+
|----|------|-----|----------|
122+
| 1 | A | 20 | 1 |
123+
| 2 | B | 21 | 1 |
124+
| 3 | C | 22 | null |
125+
| 4 | D | 23 | 2 |
126+
127+
If you will try to run COUNT and give it the values in batch_id column, it will return 3. Because there are 3 not null values in the column. This is different from number of rows in the students table.
128+
129+
Let's see how do you use this operation in SQL.
130+
131+
```sql
132+
SELECT COUNT(batch_id) FROM students;
133+
```
134+
135+
To understand how aggregate functions work via a pseudocode, let's see how SQL query optimizer may execute them.
136+
137+
```python
138+
table = []
139+
140+
count = 0
141+
142+
for row in table:
143+
if row[batch_id] is not null:
144+
count += 1
145+
146+
print(count)
147+
```
148+
149+
Few things to note here:
150+
While printing, do we have access to the values of row? Nope. We only have access to the count variable. So, we can only print the count. Extrapolating this point, when you use aggregate functions, you can only print the result of the aggregate function. You cannot print the values of the rows.
151+
152+
Eg:
153+
154+
```sql
155+
SELECT COUNT(batch_id), batch_id FROM students;
156+
```
157+
158+
This will be an invalid query. Because, you are trying to print the values of `batch_id` column as well as the count of `batch_id` column. But, you can only print the count of `batch_id` column.
159+
160+
### LIMIT Clause
161+
162+
And now let's discuss the last clause for the day. LIMIT clause allows us to limit the number of rows returned by a query. Example:
163+
164+
```sql
165+
SELECT * FROM film LIMIT 10;
166+
```
167+
168+
The above query will return only 10 rows from the `film` table. If you want to return 10 rows starting from the 11th row, you can use the `OFFSET` keyword. Example:
169+
170+
```sql
171+
SELECT * FROM film LIMIT 10 OFFSET 10;
172+
```
173+
174+
The above query will return 10 rows starting from the 11th row from the `film` table.
175+
Note that in MySQL, you cannot use the `OFFSET` keyword without the `LIMIT` keyword. Example:
176+
177+
```sql
178+
SELECT * FROM film OFFSET 10;
179+
```
180+
181+
throws an error.
182+
183+
LIMIT clause is applied at the end. Just before printing the results. Taking the example of pseudocode, it works as follows:
184+
185+
```python
186+
answer = []
187+
188+
for each row in film:
189+
if row.matches(conditions in where clause) # new line from above
190+
answer.append(row)
191+
192+
answer.sort(column_names in order by clause)
193+
194+
filtered_answer = []
195+
196+
for each row in answer:
197+
filtered_answer.append(row['rating'], row['release_year'])
198+
199+
return filtered_answer[start_of_limit: end_of_limit]
200+
```
201+
202+
Thus, if your query contains ORDER BY clause, then LIMIT clause will be applied after the ORDER BY clause. Example:
203+
204+
```sql
205+
SELECT * FROM film ORDER BY title LIMIT 10;
206+
```
207+
208+
The above query will return 10 rows from the `film` table in ascending order of the `title` column.
209+
210+
211+
### ORDER BY Clause
212+
213+
Now let's discuss another important clause. ORDER BY clause allows to return values in a sorted order. Example:
214+
215+
```sql
216+
SELECT * FROM film ORDER BY title;
217+
```
218+
219+
The above query will return all the rows from the `film` table in ascending order of the `title` column. If you want to return the rows in descending order, you can use the `DESC` keyword. Example:
220+
221+
```sql
222+
SELECT * FROM film ORDER BY title DESC;
223+
```
224+
225+
You can also sort by multiple columns. Example:
226+
227+
```sql
228+
SELECT * FROM film ORDER BY title, release_year;
229+
```
230+
231+
The above query will return all the rows from the `film` table in ascending order of the `title` column and then in ascending order of the `release_year` column. Consider the second column as tie breaker. If 2 rows have same value of title, release year will be used to break tie between them. Example:
232+
233+
```sql
234+
SELECT * FROM film ORDER BY title DESC, release_year DESC;
235+
```
236+
237+
Above query will return all the rows from the `film` table in descending order of the `title` column and if tie on `title`, in descending order of the `release_year` column.
238+
239+
By the way, you can ORDER BY on a column which is not present in the SELECT clause. Example:
240+
241+
```sql
242+
SELECT title FROM film ORDER BY release_year;
243+
```
244+
245+
Let's also build the analogy of this with a pseudocode.
246+
247+
```python
248+
answer = []
249+
250+
for each row in film:
251+
if row.matches(conditions in where clause) # new line from above
252+
answer.append(row)
253+
254+
answer.sort(column_names in order by clause)
255+
256+
filtered_answer = []
257+
258+
for each row in answer:
259+
filtered_answer.append(row['rating'], row['release_year'])
260+
261+
return filtered_answer
262+
```
263+
264+
If you see, the `ORDER BY` clause is applied after the `WHERE` clause. So, first the rows are filtered based on the `WHERE` clause and then they are sorted based on the `ORDER BY` clause. And only after that are the columns that have to be printed taken out. And that's why you can sort based on columns not even in the `SELECT` clause.
265+
266+
#### ORDER BY Clause with DISTINCT keyword
267+
268+
If you also have DISTINCT in the SELECT clause, then you can only sort by columns that are present in the SELECT clause. Example:
269+
270+
```sql
271+
SELECT DISTINCT title FROM film ORDER BY release_year;
272+
```
273+
274+
The above query will give an error. You can only sort by `title` column. Example:
275+
276+
```sql
277+
SELECT DISTINCT title FROM film ORDER BY title;
278+
```
279+
280+
Why this? Because without this the results can be ambiguous. Example:
281+
282+
```sql
283+
SELECT DISTINCT title FROM film ORDER BY release_year;
284+
```
285+
286+
The above query will return all the distinct titles from the `film` table. But which `release_year` should be used to sort them? There can be multiple `release_year` for a particular `title`. So, the results will be ambiguous.
287+
288+
### Joins
289+
290+
Every SQL query we had written till now was only finding data from 1 table. Most of the queries we had written in the previous classes were on the `film` table where we applied multiple filters etc. But do you think being able to query data from a single table is enough? Let's take a scenario of Scaler. Let's say we have 2 tables as follows in the Scaler's database:
291+
292+
`batches`
293+
294+
| batch_id | batch_name |
295+
|----------|------------|
296+
| 1 | Batch A |
297+
| 2 | Batch B |
298+
| 3 | Batch C |
299+
300+
`students`
301+
302+
| student_id | first_name | last_name | batch_id |
303+
|------------|------------|-----------|----------|
304+
| 1 | John | Doe | 1 |
305+
| 2 | Jane | Doe | 1 |
306+
| 3 | Jim | Brown | 2 |
307+
| 4 | Jenny | Smith | 3 |
308+
| 5 | Jack | Johnson | 2 |
309+
310+
Suppose, someone asks you to print the name of every student, along with the name of their batch. The output should be something like:
311+
312+
| student_name | batch_name |
313+
|--------------|------------|
314+
| John | Batch A |
315+
| Jane | Batch A |
316+
| Jim | Batch B |
317+
| Jenny | Batch C |
318+
| Jack | Batch B |
319+
320+
Will you be able to get all of this data by querying over a single table? No. The `student_name` is there in the students table, while the `batch_name` is in the batches table! We somehow need a way to combine the data from both the tables. This is where joins come in. What does the word `join` mean to you?
321+
322+
Joins, as the name suggests, are a way to combine data from multiple tables. For example, if I want to combine the data from the `students` and `batches` table, I can use joins for that. Think of joins as a way to stitch rows of 2 tables together, based on the condition you specify. Example: In our case, we would want to stitch a row of students table with a row of batches table based on what? Imagine that every row of `students` I try to match with every row of `batches`. Based on what condition to be true between those will I stitch them?
323+
324+
We would want to stitch a row of students table with a row of batches table based on the `batch_id` column. This is what we call a `join condition`. A join condition is a condition that must be true between the rows of 2 tables for them to be stitched together. Let's see how we can write a join query for our example.
325+
326+
```sql
327+
SELECT students.first_name, batches.batch_name
328+
FROM students
329+
JOIN batches
330+
ON students.batch_id = batches.batch_id;
331+
```
332+
333+
Let's break down this query. The first line is the same as what we have been writing till now. We are selecting the `first_name` column from the `students` table and the `batch_name` column from the `batches` table. The next line is where the magic happens. We are using the `JOIN` keyword to tell SQL that we want to join the `students` table with the `batches` table. The next line is the join condition. We are saying that we want to join the rows of `students` table with the rows of `batches` table where the `batch_id` column of `students` table is equal to the `batch_id` column of `batches` table. This is how we write a join query.
334+
335+
Let's take an example of this on the Sakila database. Let's say for every film, we want to print its name and the language. How can we do that?
336+
337+
```sql
338+
SELECT film.title, language.name
339+
FROM film
340+
JOIN language
341+
ON film.language_id = language.language_id;
342+
```
343+
344+
Now, sometimes typing name of tables in the query can become difficult. For example, in the above query, we have to type `film` and `language` multiple times. To make this easier, we can give aliases to the tables. For example, we can give the alias `f` to the `film` table and `l` to the `language` table. We can then use these aliases in our query. Let's see how we can do that:
345+
346+
```sql
347+
SELECT f.title, l.name
348+
FROM film AS f
349+
JOIN language AS l
350+
ON f.language_id = l.language_id;
351+
```
352+

0 commit comments

Comments
 (0)