A programming language to manage relational databases.
Relational databases organize things into tables with each element in the table having a unique id/primary key. Elements in these tables can connect to elements from other tables by having a column of that connection’s unique id.
Rows are called elements and columns are called attributes. Each cell contains one value of a specific data type.
Keys in SQL have the be unique for each element and are used to define that element.
Table 1
email(natural key) | username |
---|---|
user123@example.com | user123 |
alice@example.com | alice |
bob@example.com | bob |
Table 2
post_id(surrogate key) | email(foreign key) | message |
---|---|---|
1 | user123@example.com | Hello World |
2 | alice@example.com | My Thoughts |
3 | user123@example.com | Another Post |
One of the fundamental guarantees a transaction(Sequence of CRUD operations) must satisfy for a database.
Atomicity means that a transaction either executes entirely or not at all. If part of the transaction doesn’t work then the database is not changed.
Consistency means the database only goes from one valid state to another valid state. The database can never be in a state that breaks its own internal rules. For example, an attribute always containing a consistent data type.
Isolation means that 2 transactions happening at the same time do not interfere with one another. No race conditions.
Durability means that once a database is changed those changes will persist and not be lost. This may include some form of backups.
Attributes(columns) have various properties that define their behavior/internal rules.
Most Common Data Types | Description |
---|---|
INT | Integers of 4 bytes. |
BIGINT | Integers of 8 bytes. |
FLOAT | Floating-point numbers |
VARCHAR(#) | Strings with a pre-defined length, limited to # of characters. |
TEXT | Strings of undefined length. |
DATE | Date value in ‘YYYY-MM-DD’ format. |
TIME | Time value in ‘HH:MM:SS’ format. |
DATETIME | Date and time value in ‘YYYY-MM-DD HH:MM:SS’ format. |
BOOLEAN | Boolean value representing true or false. |
CHAR(#) | Fixed-length character string. If shorter then padded with spaces. |
BLOB | Binary large object, for storing binary data. |
DECIMAL | Store fixed point decimal numbers. Often used for monetary values. |
You can specify a default value.
time DATETIME DEFAULT CURRENT_TIMESTAMP,
VARCHAR(255) is often used over TEXT because it takes up less space.
SQL is a language used to interact with relational databases. Tends to retrieve data very fast.
--
s and /**/
s are used for comments in SQL-- Creating a new database
CREATE DATABASE record_company;
-- This tells SQL which database to use when using commands.
USE record_company;
-- Sees what database is in use
SELECT DATABASE();
-- List Databases
-- MySQL
SHOW DATABASES;
-- Deleting a databases
DROP DATABASE record_company;
-- In your schema.sql you usually run this at the beginning
DROP DATABASE IF EXISTS sample_db;
CREATE DATABASE sample_db;
-- Creating 2 new table
CREATE TABLE bands (
id INT NOT NULL AUTO_INCREMENT, -- NOT NULL means it has to have a value
name VARCHAR(255) NOT NULL UNIQUE, -- Enforces the name column/attribute to be unique
favorite_band INT,
PRIMARY KEY (id), -- Sets the primary key for the table
FOREIGN KEY (favorite_band) REFERENCES bands(id) -- Sets an internal reference
);
CREATE TABLE albums (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, -- You can also create a primary key inline
name VARCHAR(255) NOT NULL,
release_year INT, -- Can have NULL values
band_id INT NOT NULL,
FOREIGN KEY (band_id) REFERENCES bands(id), -- Sets a foreign key for band_id from the id attribute/column in the bands table
ON DELETE SET NULL -- When something is deleted it is set to null
);
-- Adding another column
ALTER TABLE bands
ADD another_column VARCHAR(255);
-- Deleting columns from tables
ALTER TABLE bands
DROP COLUMN another_column;
-- Showing tables
-- MySQL
SHOW TABLES;
-- Shows the different columns and their properties
DESCRIBE table_name;
-- Deleting a table
DROP TABLE table_name;
-- Adding elements
INSERT INTO table_name (column_1, foreign_key)
VALUES
('1st element in column 1', 1),
('2nd element in column 1', NULL);
-- Gets all attributes and all elements for that table.
SELECT * FROM table_name;
-- Get the first 2 elements of the table
SELECT * FROM table_name LIMIT 2;
-- Gets the 2nd element
SELECT * FROM table_name LIMIT 1,1; -- Limit offset, count
-- Gets all the elements, but only those columns of that element
SELECT column_1 FROM table_name;
SELECT column_1, column_2 FROM table_name;
-- Returns the column with a different name for the column
SELECT id AS 'ID', column_1 AS 'Column 1'
FROM table_name;
-- Get elements, but ordered by a different column. If the column is a text is does by alphabetical order.
SELECT * FROM table_name ORDER BY column_1;
-- or descending order
SELECT * FROM table_name ORDER BY column_1 DESC;
-- Only get unique elements from a column
SELECT DISTINCT column_1 FROM table_name;
-- Only returns the elements with an id greater than 1
SELECT * FROM table_name
WHERE id > 1;
-- Gets column1 and column2 from table_name and adds to it the dbs and the tables in those dbs
SELECT column1, column2 FROM table_name
UNION ( -- Adds onto another query
-- Gets all the dbs and the tables in those dbs
-- information_schema.tables is inbuilt into SQL
SELECT TABLE_SCHEMA AS 'databases', TABLE_NAME as 'tables' FROM information_schema.tables
WHERE
TABLE_SCHEMA != 'mysql' AND
TABLE_SCHEMA != 'information_schema' AND
TABLE_SCHEMA != 'performance_schema' AND
TABLE_SCHEMA != 'sys'
);
-- Updating elements
UPDATE table_name
SET column_1 = 'name'
WHERE id = 1;
-- Deletes the first element from a table
DELETE FROM table_name
WHERE id = 1;
-- Deletes all the rows in a table
DELETE FROM table_name;
Used to filter rows/elements based upon specific conditions.
Operator | Description |
---|---|
= | Equal to |
<> or != | Not equal to |
< | less than |
> | greater than |
<= | Less than or equal to |
>= | Greater than or equal to |
AND | Logical and |
OR | Logical or |
NOT | Logical not |
IS NULL | Is it equal to null |
BETWEEN | BETWEEN 2000 AND 2018; |
LIKE | Search for pattern. |
LIKE
is used to search for a specific string pattern.
%
means zero or more characters.
_
means a single character.
-- Selects all names starting with J
SELECT * FROM customers
WHERE customer_name LIKE 'J%';
-- Selects all names with 5 characters or Bob
SELECT * FROM customers
WHERE customer_name LIKE '_____' OR customer_name = 'Bob';
The JOIN command is used to get data from 2 or more tables.
Types of JOIN commands:
Ex:
tableA
a_id | name |
---|---|
1 | apple |
2 | orange |
3 | tomato |
4 | cucumber |
tableB
b_id | name |
---|---|
A | apple |
B | banana |
C | cucumber |
D | dill |
For every row in tableB all rows from tableA are added.
SELECT * FROM tableA
CROSS JOIN tableB;
a_id | name | b_id | name |
---|---|---|---|
4 | cucumber | A | apple |
3 | tomato | A | apple |
2 | orange | A | apple |
1 | apple | A | apple |
4 | cucumber | B | banana |
3 | tomato | B | banana |
2 | orange | B | banana |
1 | apple | B | banana |
4 | cucumber | C | cucumber |
3 | tomato | C | cucumber |
2 | orange | C | cucumber |
1 | apple | C | cucumber |
4 | cucumber | D | dill |
3 | tomato | D | dill |
2 | orange | D | dill |
1 | apple | D | dill |
Mergers only the matching rows in both tables.
By default join is an inner join.
SELECT * FROM tableA
INNER JOIN tableB
ON tableA.name = tableB.name;
--or
SELECT * FROM tableA
JOIN tableB
ON tableA.name = tableB.name;
a_id | name | b_id | name |
---|---|---|---|
1 | apple | A | apple |
4 | cucumber | C | cucumber |
Returns matched and unmatched rows from both tables. If there is no match the other side will contain null.
SELECT * FROM tableA
FULL OUTER JOIN tableB
ON tableA.name = tableB.name;
-- There is no FULL OUTER JOIN in MySQL
SELECT * FROM tableA
LEFT JOIN tableB ON tableA.name = tableB.name
UNION ALL
SELECT * FROM tableA
RIGHT JOIN tableB ON tableA.name = tableB.name
WHERE tableA.name IS NULL;
a_id | name | b_id | name |
---|---|---|---|
1 | apple | A | apple |
2 | orange | NULL | NULL |
3 | tomato | NULL | NULL |
4 | cucumber | C | cucumber |
NULL | NULL | B | banana |
NULL | NULL | D | dill |
Returns all rows from the left table(tableA) with the matching rows from the right table(tableB) or null.
SELECT * FROM tableA
LEFT OUTER JOIN tableB
ON tableA.name = tableB.name;
a_id | name | b_id | name |
---|---|---|---|
1 | apple | A | apple |
2 | orange | NULL | NULL |
3 | tomato | NULL | NULL |
4 | cucumber | C | cucumber |
Returns all rows from the right table(tableB) with the matching rows from the left table(tableA) or null.
SELECT * FROM tableA
RIGHT OUTER JOIN tableB
ON tableA.name = tableB.name;
a_id | name | b_id | name |
---|---|---|---|
1 | apple | A | apple |
4 | cucumber | C | cucumber |
NULL | NULL | B | banana |
NULL | NULL | D | dill |
Columns with the same values appear only once.
SELECT * FROM tableA
NATURAL JOIN tableB;
name | a_id | b_id |
---|---|---|
apple | 1 | A |
cucumber | 4 | C |
Returns all the rows in tableA and tableB that don’t match.
SELECT * FROM tableA
FULL OUTER JOIN tableB
ON tableA.name = tableB.name
WHERE tableA.name IS NULL tableB.name IS NULL;
a_id | name | b_id | name |
---|---|---|---|
2 | orange | NULL | NULL |
3 | tomato | NULL | NULL |
NULL | NULL | B | banana |
NULL | NULL | D | dill |
Returns all the rows in tableA that don’t match any rows in tableB.
SELECT * FROM tableA
LEFT JOIN tableB
ON tableA.name = tableB.name
WHERE tableB.name IS NULL;
a_id | name | b_id | name |
---|---|---|---|
2 | orange | NULL | NULL |
3 | tomato | NULL | NULL |
Returns all the rows in tableB that don’t match any rows in tableA.
SELECT * FROM tableA
RIGHT JOIN tableB
ON tableA.name = tableB.name
WHERE tableA.name IS NULL;
a_id | name | b_id | name |
---|---|---|---|
NULL | NULL | B | banana |
NULL | NULL | D | dill |
You can use join to dereference references. Whenever you have columns with the same name for different tables you need to specify which one you are referring to.
SELECT albums.id, albums.name, release_year AS 'release year', bands.name
FROM albums
JOIN bands ON albums.band_id = bands.id;
This returns the table:
| id | name | release year | name |
|------|---------------------------|--------------|---------------------|
| 1 | 'The Number of the Beast' | 1982 | 'Iron Maiden' |
| 2 | 'Power Slave' | 1984 | 'Iron Maiden' |
| 3 | 'Nightmare' | 2018 | 'Deuce' |
| 4 | 'Nightmare' | 2010 | 'Avenged Sevenfold' |
Functions are almost always slower than doing checks(=, !=, >, <, etc) with hard coded data values. This is because the database can quickly find the row in which the hard coded data is in.
Name | Type | Description |
---|---|---|
CONCAT() | String | Concatenates 2 or more strings |
UPPER() | String | Converts string to uppercase |
LOWER() | String | Converts string to lowercase |
LENGTH() | String | Gets the length of the string |
SUM() | Numeric | Calculates the sum of numbers |
AVG() | Numeric | Calculates the average of numbers |
COUNT() | Numeric | Counts the number of rows or non-null values |
MIN() | Numeric | Finds the minimum value in a column |
MAX() | Numeric | Finds the maximum value in a column |
DATEPART() | Date/Time | Extracts a specific part from a date or time |
DATEDIFF() | Date/Time | Calculates the difference between two dates |
CASE | Conditional | Performs conditional logic |
COALESCE() | Conditional | Returns the first non-null value in a list |
GROUP BY | Aggregation | Groups rows based on one or more columns |
HAVING | Aggregation | Filters aggregated results |
ORDER BY | Aggregation | Sorts the result set |
ROW_NUMBER() | Window | Assigns a unique row number to each row |
LAG() | Window | Accesses the value of a previous row |
MONTH() | Numeric | Gets month between 1 and 12 |
Examples:
-- AVG
SELECT AVG(release_year) FROM albums;
-- 1998.5 It doesn't count null values
-- Count
SELECT COUNT(release_year) FROM albums;
-- 4
Takes all the rows and groups them by a single column. If there are 2 rows that have the same value in a column group by combines them.
This is often used with COUNT
in order to count how many rows are in each column.
SELECT band_id, COUNT(band_id) from albums
GROUP BY band_id;
This returns the table:
| band_id | COUNT(band_id) |
|---------|----------------|
| 1 | 2 |
| 2 | 1 |
| 3 | 1 |
The HAVING
is the same as where, but happens after the GROUP BY
so you can use data before an aggravate function.
-- Get the number of bands with only 1 album
SELECT b.name band_name, COUNT(a.id) num_albums
FROM bands b
LEFT JOIN albums a ON b.id = a.band_id
GROUP BY b.id
HAVING num_albums = 1;
Alias tables are temporary names given to a table or column in order to resolve naming conflicts.
This is often used to de-reference an internal reference in a table.
SELECT b.name AS band_name, COUNT(a.id) AS num_albums
FROM bands AS b
LEFT JOIN albums AS a;
-- You can also leave out the AS
SELECT b.name band_name, COUNT(a.id) num_albums
FROM bands b
LEFT JOIN albums a;
You can have variables(user defined values) in sql by using the @
symbol.
SET @var = 1;
SELECT @var FROM table_name; -- Gets teh 1st column from table_name
Indexes are used to speed up queries in exchange for taking up more memory and increasing times to create data.
CREATE INDEX index_name ON table_name (column1, column2);
When the database creates an index it aligns everything in order(numerically or alphabetically) and creates a balanced tree to speed up queries.
A balanced tree is a binary tree where the left tree and the right tree cannot have a difference greater than 1.
Without indexing:
1->2->3->4->5->6->7->8->9->10
Is x == 1?
If no then is x == 2?
If no then is x == 3?
etc.
With indexing:
5
/ \
3 8
/ \ / \
2 4 7 9
/ \
1 10
Is x == 5?
If no then is x < 5?
If yes then is x == 3?
If no then is x < 3?
etc.
If no then is x == 8?
If no then is x < 8?
etc.
User
has one Profile
and a Profile
belongs to one User
User
has many Task
s, but a Task
belongs to only one User
Students
can belong to many Courses
and each Course
can have many Students
A special software program used to create and maintain a database.
Databases are usually kept on separate servers than your http endpoints(NodeJS and Express) because it is much easier to scale the database, secure the database, backup and recover the database, etc.
The default port for MySQL is 3306.
SOURCE schema.sql
allows you to run a sql file in MySQL.
sudo apt update
sudo apt install mysql-server
sudo mysql -u root -p
root
ALTER USER 'root'@'localhost' IDENTIFIED WITH 'mysql_native_password' BY 'new_password';
FLUSH PRIVILEGES;
exit
mysql -u root -p
to start you mysql server in the future