MySQL Tutorial - MySQL by Examples For Beginners
MySQL Tutorial - MySQL by Examples For Beginners
-- Row-Level
INSERT INTO tableName
VALUES (column1Value, column2Value,...) -- Insert on all Columns
INSERT INTO tableName
VALUES (column1Value, column2Value,...), ... -- Insert multiple rows
INSERT INTO tableName (column1Name, ..., columnNName)
VALUES (column1Value, ..., columnNValue) -- Insert on selected Columns
DELETE FROM tableName WHERE criteria
UPDATE tableName SET columnName = expr, ... WHERE criteria
SELECT * | column1Name AS alias1, ..., columnNName AS aliasN
FROM tableName
WHERE criteria
GROUP BY columnName
ORDER BY columnName ASC|DESC, ...
HAVING groupConstraints
LIMIT count | offset count
-- Others
SHOW WARNINGS; -- Show the warnings of the previous statement
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 1/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
2. An Example for the Beginners (But NOT for the dummies)
A MySQL database server contains many databases (or schemas). Each database consists of one or more tables. A table is made up of
columns (or fields) and rows (records).
The SQL keywords and commands are NOT case-sensitive. For clarity, they are shown in uppercase. The names or identifiers (database
names, table names, column names, etc.) are case-sensitive in some systems, but not in other systems. Hence, it is best to treat
identifiers as case-sensitive.
SHOW DATABASES
You can use SHOW DATABASES to list all the existing databases in the server.
The databases "mysql", "information_schema" and "performance_schema" are system databases used internally by MySQL. A
"test" database is provided during installation for your testing.
Let us begin with a simple example - a product sales database. A product sales database typically consists of many tables, e.g.,
products, customers, suppliers, orders, payments, employees, among others. Let's call our database "southwind" (inspired from
Microsoft's Northwind Trader sample database). We shall begin with the first table called "products" with the following columns
(having data types as indicated) and rows:
Database: southwind
Table: products
IMPORTANT: Use SQL DROP (and DELETE) commands with extreme care, as the deleted entities are irrecoverable. THERE IS NO
UNDO!!!
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 2/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
For robustness, the SHOW command back-quotes all the identifiers, as illustrated in the above example.
The /*!40100 ...... */ is known as version comment, which will only be run if the server is at or above this version number
4.01.00. To check the version of your MySQL server, issue query "SELECT version()".
In our example, we have a database named "southwind" with a table named "products". If we issue "USE southwind" to set
southwind as the default database, we can simply call the table as "products". Otherwise, we need to reference the table as
"southwind.products".
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 3/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
Empty set (0.00 sec)
-- Create the table "products". Read "explanations" below for the column defintions
mysql> CREATE TABLE IF NOT EXISTS products (
productID INT UNSIGNED NOT NULL AUTO_INCREMENT,
productCode CHAR(3) NOT NULL DEFAULT '',
name VARCHAR(30) NOT NULL DEFAULT '',
quantity INT UNSIGNED NOT NULL DEFAULT 0,
price DECIMAL(7,2) NOT NULL DEFAULT 99999.99,
PRIMARY KEY (productID)
);
Query OK, 0 rows affected (0.08 sec)
-- Show all the tables to confirm that the "products" table has been created
mysql> SHOW TABLES;
+---------------------+
| Tables_in_southwind |
+---------------------+
| products |
+---------------------+
-- Show the complete CREATE TABLE statement used by MySQL to create this table
mysql> SHOW CREATE TABLE products \G
*************************** 1. row ***************************
Table: products
Create Table:
CREATE TABLE `products` (
`productID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`productCode` char(3) NOT NULL DEFAULT '',
`name` varchar(30) NOT NULL DEFAULT '',
`quantity` int(10) unsigned NOT NULL DEFAULT '0',
`price` decimal(7,2) NOT NULL DEFAULT '99999.99',
PRIMARY KEY (`productID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Explanations
We define 5 columns in the table products: productID, productCode, name, quantity and price. The types are:
productID is INT UNSIGNED - non-negative integers.
productCode is CHAR(3) - a fixed-length alphanumeric string of 3 characters.
name is VARCHAR(30) - a variable-length string of up to 30 characters.
We use fixed-length string for productCode, as we assume that the productCode contains exactly 3 characters. On the other
hand, we use variable-length string for name, as its length varies - VARCHAR is more efficient than CHAR.
quantity is also INT UNSIGNED (non-negative integers).
price is DECIMAL(10,2) - a decimal number with 2 decimal places.
DECIMAL is precise (represented as integer with a fix decimal point). On the other hand, FLOAT and DOUBLE (real numbers) are
not precise and are approximated. DECIMAL type is recommended for currency.
The attribute "NOT NULL" specifies that the column cannot contain the NULL value. NULL is a special value indicating "no value",
"unknown value" or "missing value". In our case, these columns shall have a proper value. We also set the default value of the
columns. The column will take on its default value, if no value is specified during the record creation.
We set the column productID as the so-called primary key. Values of the primary-key column must be unique. Every table shall
contain a primary key. This ensures that every row can be distinguished from other rows. You can specify a single column or a set of
columns (e.g., firstName and lastName) as the primary key. An index is build automatically on the primary-key column to facilitate
fast search. Primary key is also used as reference by other tables.
We set the column productID to AUTO_INCREMENT. with default starting value of 1. When you insert a row with NULL
(recommended) (or 0, or a missing value) for the AUTO_INCREMENT column, the maximum value of that column plus 1 would be
inserted. You can also insert a valid value to an AUTO_INCREMENT column, bypassing the auto-increment.
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 4/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
You need to list the values in the same order in which the columns are defined in the CREATE TABLE, separated by commas. For
columns of string data type (CHAR, VARCHAR), enclosed the value with a pair of single quotes (or double quotes). For columns of
numeric data type (INT, DECIMAL, FLOAT, DOUBLE), simply place the number.
You can also insert multiple rows in one INSERT INTO statement:
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 5/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
(column1Name, ..., columnNName)
VALUES
(row1column1Value, ..., row2ColumnNValue),
(row2column1Value, ..., row2ColumnNValue),
...
The remaining columns will receive their default value, such as AUTO_INCREMENT, default, or NULL.
-- List all the rows of ALL columns, * is a wildcard denoting all columns
SELECT * FROM tableName
For examples,
-- List all rows of ALL the columns. The wildcard * denotes ALL columns
mysql> SELECT * FROM products;
+-----------+-------------+-----------+----------+-------+
| productID | productCode | name | quantity | price |
+-----------+-------------+-----------+----------+-------+
| 1001 | PEN | Pen Red | 5000 | 1.23 |
| 1002 | PEN | Pen Blue | 8000 | 1.25 |
| 1003 | PEN | Pen Black | 2000 | 1.25 |
| 1004 | PEC | Pencil 2B | 10000 | 0.48 |
| 1005 | PEC | Pencil 2H | 8000 | 0.49 |
+-----------+-------------+-----------+----------+-------+
5 rows in set (0.00 sec)
// Multiple columns
mysql> SELECT 1+1, NOW();
+-----+---------------------+
| 1+1 | NOW() |
+-----+---------------------+
| 2 | 2012-10-24 22:16:34 |
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 6/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
+-----+---------------------+
1 row in set (0.00 sec)
Comparison Operators
For numbers (INT, DECIMAL, FLOAT), you could use comparison operators: '=' (equal to), '<>' or '!=' (not equal to), '>' (greater
than), '<' (less than), '>=' (greater than or equal to), '<=' (less than or equal to), to compare two numbers. For example, price >
1.0, quantity <= 500.
mysql> SELECT name, price FROM products WHERE price < 1.0;
+-----------+-------+
| name | price |
+-----------+-------+
| Pencil 2B | 0.48 |
| Pencil 2H | 0.49 |
+-----------+-------+
2 rows in set (0.00 sec)
mysql> SELECT name, quantity FROM products WHERE quantity <= 2000;
+-----------+----------+
| name | quantity |
+-----------+----------+
| Pen Black | 2000 |
+-----------+----------+
1 row in set (0.00 sec)
CAUTION: Do not compare FLOATs (real numbers) for equality ('=' or '<>'), as they are not precise. On the other hand, DECIMAL are
precise.
For strings, you could also use '=', '<>', '>', '<', '>=', '<=' to compare two strings (e.g., productCode = 'PEC'). The
ordering of string depends on the so-called collation chosen. For example,
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 7/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
| Pen Black | 1.25 |
+-----------+-------+
MySQL also support regular expression matching via the REGEXE operator.
Arithmetic Operators
You can perform arithmetic operations on numeric fields using arithmetic operators, as tabulated below:
Operator Description
+ Addition
- Subtraction
* Multiplication
/ Division
DIV Integer Division
% Modulus (Remainder)
mysql> SELECT * FROM products WHERE quantity >= 5000 AND name LIKE 'Pen %';
+-----------+-------------+----------+----------+-------+
| productID | productCode | name | quantity | price |
+-----------+-------------+----------+----------+-------+
| 1001 | PEN | Pen Red | 5000 | 1.23 |
| 1002 | PEN | Pen Blue | 8000 | 1.25 |
+-----------+-------------+----------+----------+-------+
mysql> SELECT * FROM products WHERE quantity >= 5000 AND price < 1.24 AND name LIKE 'Pen %';
+-----------+-------------+---------+----------+-------+
| productID | productCode | name | quantity | price |
+-----------+-------------+---------+----------+-------+
| 1001 | PEN | Pen Red | 5000 | 1.23 |
+-----------+-------------+---------+----------+-------+
mysql> SELECT * FROM products WHERE NOT (quantity >= 5000 AND name LIKE 'Pen %');
+-----------+-------------+-----------+----------+-------+
| productID | productCode | name | quantity | price |
+-----------+-------------+-----------+----------+-------+
| 1003 | PEN | Pen Black | 2000 | 1.25 |
| 1004 | PEC | Pencil 2B | 10000 | 0.48 |
| 1005 | PEC | Pencil 2H | 8000 | 0.49 |
+-----------+-------------+-----------+----------+-------+
IN, NOT IN
You can select from members of a set with IN (or NOT IN) operator. This is easier and clearer than the equivalent AND-OR expression.
mysql> SELECT * FROM products WHERE name IN ('Pen Red', 'Pen Black');
+-----------+-------------+-----------+----------+-------+
| productID | productCode | name | quantity | price |
+-----------+-------------+-----------+----------+-------+
| 1001 | PEN | Pen Red | 5000 | 1.23 |
| 1003 | PEN | Pen Black | 2000 | 1.25 |
+-----------+-------------+-----------+----------+-------+
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 8/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
NULL is a special value, which represent "no value", "missing value" or "unknown value". You can checking if a column contains NULL
by IS NULL or IS NOT NULL. For example,
Using comparison operator (such as = or <>) to check for NULL is a mistake - a very common mistake. For example,
ORDER BY Clause
You can order the rows selected using ORDER BY clause, with the following syntax:
The selected row will be ordered according to the values in columnA, in either ascending (ASC) (default) or descending (DESC) order.
If several rows have the same value in columnA, it will be ordered according to columnB, and so on. For strings, the ordering could be
case-sensitive or case-insensitive, depending on the so-called character collating sequence used. For examples,
You can randomize the returned records via function RAND(), e.g.,
LIMIT Clause
A SELECT query on a large database may produce many rows. You could use the LIMIT clause to limit the number of rows displayed,
e.g.,
To continue to the following records , you could specify the number of rows to be skipped, followed by the number of rows to be
displayed in the LIMIT clause, as follows:
-- Skip the first two rows and display the next 1 row
mysql> SELECT * FROM products ORDER BY price LIMIT 2, 1;
+-----------+-------------+---------+----------+-------+
| productID | productCode | name | quantity | price |
+-----------+-------------+---------+----------+-------+
| 1001 | PEN | Pen Red | 5000 | 1.23 |
+-----------+-------------+---------+----------+-------+
AS - Alias
You could use the keyword AS to define an alias for an identifier (such as column name, table name). The alias will be used in
displaying the name. It can also be used as reference. For example,
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 9/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
Take note that the identifier "Unit Price" contains a blank and must be back-quoted.
Function CONCAT()
You can also concatenate a few columns as one (e.g., joining the last name and first name) using function CONCAT(). For example,
mysql> SELECT CONCAT(productCode, ' - ', name) AS `Product Description`, price FROM products;
+---------------------+-------+
| Product Description | price |
+---------------------+-------+
| PEN - Pen Red | 1.23 |
| PEN - Pen Blue | 1.25 |
| PEN - Pen Black | 1.25 |
| PEC - Pencil 2B | 0.48 |
| PEC - Pencil 2H | 0.49 |
+---------------------+-------+
DISTINCT
A column may have duplicate values, we could use keyword DISTINCT to select only distinct values. We can also apply DISTINCT to
several columns to select distinct combinations of these columns. For examples,
-- Without DISTINCT
mysql> SELECT price FROM products;
+-------+
| price |
+-------+
| 1.23 |
| 1.25 |
| 1.25 |
| 0.48 |
| 0.49 |
+-------+
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 10/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
GROUP BY Clause
The GROUP BY clause allows you to collapse multiple records with a common value into groups. For example,
GROUP BY by itself is not meaningful. It is used together with GROUP BY aggregate functions (such as COUNT(), AVG(), SUM()) to
produce group summary.
GROUP BY Aggregate Functions: COUNT, MAX, MIN, AVG, SUM, STD, GROUP_CONCAT
We can apply GROUP BY Aggregate functions to each group to produce group summary report.
The function COUNT(*) returns the rows selected; COUNT(columnName) counts only the non-NULL values of the given column. For
example,
Besides COUNT(), there are many other GROUP BY aggregate functions such as AVG(), MAX(), MIN() and SUM(). For example,
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 11/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
| productCode | Highest Price | Lowest Price |
+-------------+---------------+--------------+
| PEC | 0.49 | 0.48 |
| PEN | 1.25 | 1.23 |
+-------------+---------------+--------------+
HAVING clause
HAVING is similar to WHERE, but it can operate on the GROUP BY aggregate functions; whereas WHERE operates only on columns.
mysql> SELECT
productCode AS `Product Code`,
COUNT(*) AS `Count`,
CAST(AVG(price) AS DECIMAL(7,2)) AS `Average`
FROM products
GROUP BY productCode
HAVING Count >=3;
-- CANNOT use WHERE count >= 3
+--------------+-------+---------+
| Product Code | Count | Average |
+--------------+-------+---------+
| PEN | 3 | 1.24 |
+--------------+-------+---------+
WITH ROLLUP
The WITH ROLLUP clause shows the summary of group summary, e.g.,
mysql> SELECT
productCode,
MAX(price),
MIN(price),
CAST(AVG(price) AS DECIMAL(7,2)) AS `Average`,
SUM(quantity)
FROM products
GROUP BY productCode
WITH ROLLUP; -- Apply aggregate functions to all groups
+-------------+------------+------------+---------+---------------+
| productCode | MAX(price) | MIN(price) | Average | SUM(quantity) |
+-------------+------------+------------+---------+---------------+
| PEC | 0.49 | 0.48 | 0.49 | 18000 |
| PEN | 1.25 | 1.23 | 1.24 | 15000 |
| NULL | 1.25 | 0.48 | 0.94 | 33000 |
+-------------+------------+------------+---------+---------------+
For example,
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 12/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
| 1003 | PEN | Pen Black | 2000 | 1.38 |
| 1004 | PEC | Pencil 2B | 10000 | 0.53 |
| 1005 | PEC | Pencil 2H | 8000 | 0.54 |
+-----------+-------------+-----------+----------+-------+
CAUTION: If the WHERE clause is omitted in the UPDATE command, ALL ROWS will be updated. Hence, it is a good practice to issue a
SELECT query, using the same criteria, to check the result set before issuing the UPDATE. This also applies to the DELETE statement
in the following section.
-- Delete all rows from the table. Use with extreme care! Records are NOT recoverable!!!
DELETE FROM tableName
-- Delete only row(s) that meets the criteria
DELETE FROM tableName WHERE criteria
For example,
-- Use this with extreme care, as the deleted records are irrecoverable!
mysql> DELETE FROM products;
Query OK, 3 rows affected (0.00 sec)
Beware that "DELETE FROM tableName" without a WHERE clause deletes ALL records from the table. Even with a WHERE clause, you
might have deleted some records unintentionally. It is always advisable to issue a SELECT command with the same WHERE clause to
check the result set before issuing the DELETE (and UPDATE).
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 13/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
\N,PEC,Pencil 3B,500,0.52
\N,PEC,Pencil 4B,200,0.62
\N,PEC,Pencil 5B,100,0.73
\N,PEC,Pencil 6B,500,0.47
You can load the raw data into the products table as follows:
(For Windows)
-- Need to use forward-slash (instead of back-slash) as directory separator
mysql> LOAD DATA LOCAL INFILE 'd:/myProject/products_in.csv' INTO TABLE products
COLUMNS TERMINATED BY ','
LINES TERMINATED BY '\r\n';
(For Macs)
mysql> LOAD DATA LOCAL INFILE '~/Documents/products_in.csv' INTO TABLE products
COLUMNS TERMINATED BY ',';
Notes:
You need to provide the path (absolute or relative) and the filename. Use Unix-style forward-slash '/' as the directory separator,
instead of Windows-style back-slash '\'.
The default line delimiter (or end-of-line) is '\n' (Unix-style). If the text file is prepared in Windows, you need to include LINES
TERMINATED BY '\r\n'.
The default column delimiter is "tab" (in a so-called TSV file - Tab-Separated Values). If you use another delimiter, e.g. ',', include
COLUMNS TERMINATED BY ','.
You need to use \N for NULL.
-- SYNTAX
> mysqlimport -u username -p --local databaseName tableName.tsv
-- The raw data must be kept in a TSV (Tab-Separated Values) file with filename the same as tablename
-- EXAMPLES
-- Create a new file called "products.tsv" containing the following record,
-- and saved under "d:\myProject" (for Windows) or "Documents" (for Mac)
-- The values are separated by tab (not spaces).
\N PEC Pencil 3B 500 0.52
\N PEC Pencil 4B 200 0.62
\N PEC Pencil 5B 100 0.73
\N PEC Pencil 6B 500 0.47
(For Windows)
> cd path-to-mysql-bin
> mysqlimport -u root -p --local southwind d:/myProject/products.tsv
(For Macs)
$ cd /usr/local/mysql/bin
$ ./mysqlimport -u root -p --local southwind ~/Documents/products.tsv
(For Windows)
mysql> SELECT * FROM products INTO OUTFILE 'd:/myProject/products_out.csv'
COLUMNS TERMINATED BY ','
LINES TERMINATED BY '\r\n';
(For Macs)
mysql> SELECT * FROM products INTO OUTFILE '~/Documents/products_out.csv'
COLUMNS TERMINATED BY ',';
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 14/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
(For Windows)
mysql> source d:/myProject/load_products.sql
-- Use Unix-style forward slash (/) as directory separator
(For Macs)
mysql> source ~/Documents/load_products.sql
2. via the "batch mode" of the mysql client program, by re-directing the input from the script:
(For Windows)
> cd path-to-mysql-bin
> mysql -u root -p southwind < d:\myProject\load_products.sql
(For Macs)
$ cd /usr/local/mysql/bin
$ ./mysql -u root -p southwind < ~\Documents\load_products.sql
Products have suppliers. If each product has one supplier, and each supplier supplies only one product (known as one-to-one
relationship), we can simply add the supplier's data (name, address, phone number) into the products table. Suppose that each
product has one supplier, and a supplier may supply zero or more products (known as one-to-many relationship). Putting the supplier's
data into the products table results in duplication of data. This is because one supplier may supply many products, hence, the same
supplier's data appear in many rows. This not only wastes the storage but also easily leads to inconsistency (as all duplicate data must
be updated simultaneously). The situation is even more complicated if one product has many suppliers, and each supplier can supply
many products, in a many-to-many relationship.
3.1 One-To-Many Relationship
Suppose that each product has one supplier, and each supplier supplies one or more products. We could create a table called
suppliers to store suppliers' data (e.g., name, address and phone number). We create a column with unique value called
supplierID to identify every suppliers. We set supplierID as the primary key for the table suppliers (to ensure uniqueness and
facilitate fast search).
To relate the suppliers table to the products table, we add a new column into the products table - the supplierID. We then
set the supplierID column of the products table as a foreign key references the supplierID column of the suppliers table to
ensure the so-called referential integrity.
Database: southwind
Table: suppliers
Database: southwind
Table: products
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 15/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
We need to first create the suppliers table, because the products table references the suppliers table. The suppliers table is
known as the parent table; while the products table is known as the child table in this relationship.
ALTER TABLE
Instead of deleting and re-creating the products table, we shall use "ALTER TABLE" to add a new column supplierID into the
products table.
Next, we shall add a foreign key constraint on the supplierID columns of the products child table to the suppliers parent table,
to ensure that every supplierID in the products table always refers to a valid supplierID in the suppliers table - this is called
referential integrity.
Before we can add the foreign key, we need to set the supplierID of the existing records in the products table to a valid
supplierID in the suppliers table (say supplierID=501).
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 16/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
-- Set the supplierID of the existing records in "products" table to a VALID supplierID
-- of "suppliers" table
mysql> UPDATE products SET supplierID = 501;
In the above query result, two of the columns have the same heading "name". We could create aliases for headings.
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 17/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
JOIN suppliers AS s ON p.supplierID = s.supplierID
WHERE p.price < 0.6;
The database diagram is as illustrated. The link indicates a one-to-many relationship between products and suppliers.
3.2 Many-To-Many Relationship
Suppose that a product has many suppliers; and a supplier supplies many products in a so-called many-to-many relationship. The
above solution breaks. You cannot include the supplierID in the products table, as you cannot determine the number of suppliers,
and hence, the number of columns needed for the supplierIDs. Similarly, you cannot include the productID in the suppliers
table, as you cannot determine the number of products.
To resolve this problem, you need to create a new table, known as a junction table (or joint table), to provide the linkage. Let's call the
junction table products_suppliers, as illustrated.
Database: southwind
Table: products_suppliers
productID supplierID
INT INT
(Foreign Key) (Foreign Key)
2001 501
2002 501
2003 501
2004 502
2001 503
Database: southwind
Table: suppliers
Database: southwind
Table: products
Let's create the products_suppliers table. The primary key of the table consists of two columns: productID and supplierID, as
their combination uniquely identifies each rows. This primary key is defined to ensure uniqueness. Two foreign keys are defined to set
the constraint to the two parent tables.
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 18/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
Next, remove the supplierID column from the products table. (This column was added to establish the one-to-many relationship.
It is no longer needed in the many-to-many relationship.)
Before this column can be removed, you need to remove the foreign key that builds on this column. To remove a key in MySQL, you
need to know its constraint name, which was generated by the system. To find the constraint name, issue a "SHOW CREATE TABLE
products" and take note of the foreign key's constraint name in the clause "CONSTRAINT constraint_name FOREIGN KEY
....". You can then drop the foreign key using "ALTER TABLE products DROP FOREIGN KEY constraint_name"
Querying
Similarly, we can use SELECT with JOIN to query data from the 3 tables, for examples,
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 19/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
+--------------+-------+---------------+
| Pencil 3B | 0.52 | ABC Traders |
| Pencil 3B | 0.52 | QQ Corp |
| Pencil 6B | 0.47 | XYZ Company |
+--------------+-------+---------------+
The database diagram is as follows. Both products and suppliers tables exhibit a one-to-many relationship to the junction table.
The many-to-many relationship is supported via the junction table.
3.3 One-to-one Relationship
Suppose that some products have optional data (e.g., photo, comment). Instead of keeping these optional data in the products
table, it is more efficient to create another table called product_details, and link it to products with a one-to-one relationship, as
illustrated.
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 20/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
(For Windows)
-- Start a NEW "cmd"
> cd path-to-mysql-bin
> mysqldump -u root -p --databases southwind > "d:\myProject\backup_southwind.sql"
(For Macs)
-- Start a NEW "terminal"
$ cd /usr/local/mysql/bin
$ ./mysqldump -u root -p --databases southwind > ~/Documents/backup_southwind.sql
Study the output file, which contains CREATE DATABASE, CREATE TABLE and INSERT statements to re-create the tables dumped.
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 21/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
-- Dump selected tables of a particular database
> mysqldump -u username -p databaseName table1Name [table2Name ...] > backupFile.sql
Restore: The utility mysqldump produces a SQL script (consisting of CREATE TABLE and INSERT commands to re-create the tables
and loading their data). You can restore from the backup by running the script either:
1. via the "source" command in an interactive client. For example, to restore the southwind backup earlier:
(For Windows)
-- Start a MySQL client
mysql> source d:/myProject/backup_southwind.sql
-- Provide absolute or relative filename of the script
-- Use Unix-style forward slash (/) as path separator
(For Macs)
-- Start a MySQL client
mysql> source ~/Documents/backup_southwind.sql
2. via the "batch mode" of the mysql client program by re-directing the input from the script:
(For Windows)
-- Start a NEW "cmd"
> cd path-to-mysql-bin
> mysql -u root -p southwind < d:\myProject\backup_southwind.sql
(For Macs)
-- Start a NEW "terminal"
$ cd /usr/local/mysql/bin
$ ./mysql -u root -p southwind < ~/Documents/backup_southwind.sql
4.1 Primary Key
In the relational model, a table shall not contain duplicate rows, because that would create ambiguity in retrieval. To ensure
uniqueness, each table should have a column (or a set of columns), called primary key, that uniquely identifies every record of the
table. For example, an unique number customerID can be used as the primary key for the customers table; productCode for
products table; isbn for books table. A primary key is called a simple key if it is a single column; it is called a composite key if it is
made up of several columns. Most RDBMSs build an index on the primary key to facilitate fast search. The primary key is often used to
relate to other tables.
4.2 Foreign Key
A foreign key of a child table is used to reference the parent table. Foreign key constraint can be imposed to ensure so-called
referential integrity - values in the child table must be valid values in the parent table.
We define the foreign key when defining the child table, which references a parent table, as follows:
You can specify the reference action for UPDATE and DELETE via the optional ON UPDATE and ON DELETE clauses:
1. RESTRICT (default): disallow DELETE or UPDATE of the parent's row, if there are matching rows in child table.
2. CASCADE: cascade the DELETE or UPDATE action to the matching rows in the child table.
3. SET NULL: set the foreign key value in the child table to NULL (if NULL is allowed).
4. NO ACTION: a SQL term which means no action on the parent's row. Same as RESTRICT in MySQL, which disallows DELETE or
UPDATE (do nothing).
Try deleting a record in the suppliers (parent) table that is referenced by products_suppliers (child) table, e.g.,
-- Try deleting a row from parent table with matching rows in the child table
mysql> DELETE FROM suppliers WHERE supplierID = 501;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails
(`southwind`.`products_suppliers`, CONSTRAINT `products_suppliers_ibfk_2`
FOREIGN KEY (`supplierID`) REFERENCES `suppliers` (`supplierID`))
The record cannot be deleted as the default "ON DELETE RESTRICT" constraint was imposed.
You should index columns which are frequently used in the WHERE clause; and as JOIN columns.
The drawback about indexing is cost and space. Building and maintaining indexes require computations and memory spaces. Indexes
facilitate fast search but deplete the performance on modifying the table (INSERT/UPDATE/DELETE), and need to be justified.
Nevertheless, relational databases are typically optimized for queries and retrievals, but NOT for updates.
There can be more than one indexes in a table. Index are automatically built on the primary-key column(s).
You can build index via CREATE TABLE, CREATE INDEX or ALTER TABLE.
Example
mysql> CREATE TABLE employees (
emp_no INT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
gender ENUM ('M','F') NOT NULL,
birth_date DATE NOT NULL,
hire_date DATE NOT NULL,
PRIMARY KEY (emp_no) -- Index built automatically on primary-key column
);
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 23/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
*************************** 1. row ***************************
Table: employees
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: emp_no
.......
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 24/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
........
*************************** 3. row ***************************
Table: dept_emp
Non_unique: 1
Key_name: emp_no
Seq_in_index: 1
Column_name: emp_no
........
*************************** 4. row ***************************
Table: dept_emp
Non_unique: 1
Key_name: dept_no
Seq_in_index: 1
Column_name: dept_no
........
5. More SQL
5.1 Sub-Query
Results of one query can be used in another SQL statement. Subquery is useful if more than one tables are involved.
A subquery may return a scalar, a single column, a single row, or a table. You can use comparison operator (e.g., '=', '>') on scalar, IN
or NOT IN for single row or column, EXISTS or NOT EXIST to test for empty set.
With date/time data types, you can sort the results by date, search for a particular date or a range of dates, calculate the difference
between dates, compute a new date by adding/subtracting an interval from a given date.
Date By Example
Let's begin with Date (without Time) with the following example. Take note that date value must be written as a string in the format
of 'yyyy-mm-dd', e.g., '2012-01-31'.
-- Select patients who were born in a particular year and sort by birth-month
-- Function YEAR(date), MONTH(date), DAY(date) returns
-- the year, month, day part of the given date
mysql> SELECT * FROM patients
WHERE YEAR(dateOfBirth) = 2011
ORDER BY MONTH(dateOfBirth), DAY(dateOfBirth);
+-----------+-------+-------------+---------------+---------------+
| patientID | name | dateOfBirth | lastVisitDate | nextVisitDate |
+-----------+-------+-------------+---------------+---------------+
| 1003 | Ali | 2011-01-30 | 2012-10-21 | NULL |
| 1002 | Kumar | 2011-10-29 | 2012-09-20 | NULL |
+-----------+-------+-------------+---------------+---------------+
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 26/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
SET nextVisitDate = DATE_ADD(CURDATE(), INTERVAL 6 MONTH)
WHERE name = 'Ali';
For examples,
The date/time value can be entered manually as a string literal (e.g., '2010-12-31 23:59:59' for DATAETIME). MySQL will issue a
warning and insert all zeros (e.g., '0000-00-00 00:00:00' for DATAETIME), if the value of date/time to be inserted is invalid or
out-of-range. '0000-00-00' is called a "dummy" date.
Extracting information: DAYNAME() (e.g., 'Monday'), MONTHNAME() (e.g., 'March'), DAYOFWEEK() (1=Sunday, …, 7=Saturday),
DAYOFYEAR() (1-366), ...
Computing another date/time: DATE_SUB(date, INTERVAL expr unit), DATE_ADD(date, INTERVAL expr unit),
TIMESTAMPADD(unit, interval, timestamp), e.g.,
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 27/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
Example
1. Create a table with various date/time columns. Only the TIMESTAMP column can have the DEFAULT CURRENT_TIMESTAMP and
ON UPDATE CURRENT_TIMESTAMP.
Notes:
Don't use year(2) anymore.
From MySQL 5.7, the supported range for datetime is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'.
2. Insert values manually using string literals.
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 28/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
+--------------+---------------------+------------+----------+-------+--------+---------------------+
| description | cDateTime | cDate | cTime | cYear | cYear2 | cTimeStamp |
+--------------+---------------------+------------+----------+-------+--------+---------------------+
| Manual Entry | 2001-01-01 23:59:59 | 2002-02-02 | 12:30:30 | 2004 | 05 | 2010-04-08 14:44:37 |
+--------------+---------------------+------------+----------+-------+--------+---------------------+
mysql> SELECT `cDate`, `cDate` + INTERVAL 30 DAY, `cDate` + INTERVAL 1 MONTH FROM `datetime_arena`;
+------------+---------------------------+----------------------------+
| cDate | `cDate` + INTERVAL 30 DAY | `cDate` + INTERVAL 1 MONTH |
+------------+---------------------------+----------------------------+
| 2002-02-02 | 2002-03-04 | 2002-03-02 |
| 2010-04-08 | 2010-05-08 | 2010-05-08 |
| 0000-00-00 | NULL | NULL |
+------------+---------------------------+----------------------------+
5.3 View
A view is a virtual table that contains no physical data. It provide an alternative way to look at the data.
Example
-- Define a VIEW called supplier_view from products, suppliers and products_suppliers tables
mysql> CREATE VIEW supplier_view
AS
SELECT suppliers.name as `Supplier Name`, products.name as `Product Name`
FROM products
JOIN suppliers ON products.productID = products_suppliers.productID
JOIN products_suppliers ON suppliers.supplierID = products_suppliers.supplierID;
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 29/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
| ABC Traders | Pencil 4B |
| ABC Traders | Pencil 5B |
| XYZ Company | Pencil 6B |
+---------------+--------------+
Example
mysql> DROP VIEW IF EXISTS patient_view;
5.4 Transactions
A atomic transaction is a set of SQL statements that either ALL succeed or ALL fail. Transaction is important to ensure that there is no
partial update to the database, given an atomic of SQL statements. Transactions are carried out via COMMIT and ROLLBACK.
Example
mysql> CREATE TABLE accounts (
name VARCHAR(30),
balance DECIMAL(10,2)
);
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 30/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
If you start another mysql client and do a SELECT during the transaction (before the commit or rollback), you will not see the
changes.
Alternatively, you can also disable the so-called autocommit mode, which is set by default and commit every single SQL statement.
mysql> UPDATE accounts SET balance = balance - 100 WHERE name = 'Paul';
mysql> UPDATE accounts SET balance = balance + 100 WHERE name = 'Peter';
mysql> ROLLBACK;
mysql> SELECT * FROM accounts;
+-------+---------+
| name | balance |
+-------+---------+
| Paul | 800.00 |
| Peter | 2200.00 |
+-------+---------+
A transaction groups a set of operations into a unit that meets the ACID test:
1. Atomicity: If all the operations succeed, changes are committed to the database. If any of the operations fails, the entire
transaction is rolled back, and no change is made to the database. In other words, there is no partial update.
2. Consistency: A transaction transform the database from one consistent state to another consistent state.
3. Isolation: Changes to a transaction are not visible to another transaction until they are committed.
4. Durability: Committed changes are durable and never lost.
5.5 User Variables
In MySQL, you can define user variables via:
1. @varname :=value in a SELECT command, or
2. SET @varname := value or SET @varname = value command.
For examples,
6. More on JOIN
6.1 INNER JOIN
In an inner join of two tables, each row of the first table is combined (joined) with every row of second table. Suppose that there are
n1 rows in the first table and n2 rows in the second table, INNER JOIN produces all combinations of n1×n2 rows - it is known as
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 31/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
Cartesian Product or Cross Product.
Example
mysql> DROP TABLE IF EXISTS t1, t2;
mysql> SELECT *
FROM t1 INNER JOIN t2;
+----+------------+----+------------+
| id | desc | id | desc |
+----+------------+----+------------+
| 1 | ID 1 in t1 | 2 | ID 2 in t2 |
| 2 | ID 2 in t1 | 2 | ID 2 in t2 |
| 3 | ID 3 in t1 | 2 | ID 2 in t2 |
| 1 | ID 1 in t1 | 3 | ID 3 in t2 |
| 2 | ID 2 in t1 | 3 | ID 3 in t2 |
| 3 | ID 3 in t1 | 3 | ID 3 in t2 |
| 1 | ID 1 in t1 | 4 | ID 4 in t2 |
| 2 | ID 2 in t1 | 4 | ID 4 in t2 |
| 3 | ID 3 in t1 | 4 | ID 4 in t2 |
+----+------------+----+------------+
-- SELECT all columns in t1 and t2 (*)
-- INNER JOIN produces ALL combinations of rows in t1 and t2
mysql> SELECT *
FROM t1 INNER JOIN t2 ON t1.id = t2.id;
+----+------------+----+------------+
| id | desc | id | desc |
+----+------------+----+------------+
| 2 | ID 2 in t1 | 2 | ID 2 in t2 |
| 3 | ID 3 in t1 | 3 | ID 3 in t2 |
+----+------------+----+------------+
mysql> SELECT *
FROM t1 INNER JOIN t2 ON t1.id = t2.id;
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 32/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
mysql> SELECT *
FROM t1 JOIN t2 ON t1.id = t2.id; -- default JOIN is INNER JOIN
mysql> SELECT *
FROM t1 CROSS JOIN t2 ON t1.id = t2.id; -- Also called CROSS JOIN
-- You can use USING clause if the join-columns have the same name
mysql> SELECT *
FROM t1 INNER JOIN t2 USING (id);
+----+------------+------------+
| id | desc | desc |
+----+------------+------------+
| 2 | ID 2 in t1 | ID 2 in t2 |
| 3 | ID 3 in t1 | ID 3 in t2 |
+----+------------+------------+
-- Only 3 columns in the result set, instead of 4 columns with ON clause
mysql> SELECT *
FROM t1 INNER JOIN t2 WHERE t1.id = t2.id; -- Use WHERE instead of ON
mysql> SELECT *
FROM t1, t2 WHERE t1.id = t2.id; -- Use "commas" operator to join
In a LEFT JOIN, when a row in the left table does not match with the right table, it is still selected but by combining with a "fake"
record of all NULLs for the right table.
mysql> SELECT *
FROM t1 LEFT JOIN t2 ON t1.id = t2.id;
+----+------------+------+------------+
| id | desc | id | desc |
+----+------------+------+------------+
| 1 | ID 1 in t1 | NULL | NULL |
| 2 | ID 2 in t1 | 2 | ID 2 in t2 |
| 3 | ID 3 in t1 | 3 | ID 3 in t2 |
+----+------------+------+------------+
mysql> SELECT *
FROM t1 LEFT JOIN t2 USING (id);
+----+------------+------------+
| id | desc | desc |
+----+------------+------------+
| 1 | ID 1 in t1 | NULL |
| 2 | ID 2 in t1 | ID 2 in t2 |
| 3 | ID 3 in t1 | ID 3 in t2 |
+----+------------+------------+
mysql> SELECT *
FROM t1 RIGHT JOIN t2 ON t1.id = t2.id;
+------+------------+----+------------+
| id | desc | id | desc |
+------+------------+----+------------+
| 2 | ID 2 in t1 | 2 | ID 2 in t2 |
| 3 | ID 3 in t1 | 3 | ID 3 in t2 |
| NULL | NULL | 4 | ID 4 in t2 |
+------+------------+----+------------+
mysql> SELECT *
FROM t1 RIGHT JOIN t2 USING (id);
+----+------------+------------+
| id | desc | desc |
+----+------------+------------+
| 2 | ID 2 in t2 | ID 2 in t1 |
| 3 | ID 3 in t2 | ID 3 in t1 |
| 4 | ID 4 in t2 | NULL |
+----+------------+------------+
As the result, LEFT JOIN ensures that the result set contains every row on the left table. This is important, as in some queries, you
are interested to have result on every row on the left table, with no match in the right table, e.g., searching for items without supplier.
For example,
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 33/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
WHERE t2.id IS NULL;
+----+------------+
| id | desc |
+----+------------+
| 1 | ID 1 in t1 |
+----+------------+
mysql> SELECT *
FROM t1 LEFT JOIN t2 ON t1.id = t2.id;
mysql> SELECT *
FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.id;
mysql> SELECT *
FROM t1 LEFT JOIN t2 USING (id); -- join-columns have same name
+----+------------+------------+
| id | desc | desc |
+----+------------+------------+
| 1 | ID 1 in t1 | NULL |
| 2 | ID 2 in t1 | ID 2 in t2 |
| 3 | ID 3 in t1 | ID 3 in t2 |
+----+------------+------------+
7. Exercises
7.1 Rental System
Peter runs a small car rental company with 10 cars and 5 trucks. He engages you to design a web portal to put his operation online.
For the initial phase, the web portal shall provide these basic functions:
1. Maintaining the records of the vehicles and customers.
2. Inquiring about the availability of vehicle, and
3. Reserving a vehicle for rental.
A vehicle, identified by the vehicle registration number, can be rented on a daily basis. The rental rate is different for different
vehicles. There is a discount of 20% for rental of 7 days or more.
A customer can rental a vehicle from a start date to an end date. A special customer discount, ranging from 0-50%, can be given to
preferred customers.
Database
The initial database contains 3 tables: vehicles, customers, and rental_records. The rental_records is a junction table
supporting many-to-many relationship between vehicles and customers.
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 34/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
-- The InnoDB Engine supports foreign keys and transactions
DESC `vehicles`;
SHOW CREATE TABLE `vehicles` \G
SHOW INDEX FROM `vehicles` \G
Exercises
1. Customer 'Tan Ah Teck' has rented 'SBA1111A' from today for 10 days. (Hint: You need to insert a rental record. Use a
SELECT subquery to get the customer_id. Use CURDATE() (or NOW()) for today; and DATE_ADD(CURDATE(), INTERVAL x
unit) to compute a future date.)
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 35/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
CURDATE(),
DATE_ADD(CURDATE(), INTERVAL 10 DAY),
NULL);
SELECT
r.start_date AS `Start Date`,
r.end_date AS `End Date`,
r.veh_reg_no AS `Vehicle No`,
v.brand AS `Vehicle Brand`,
c.name AS `Customer Name`
FROM rental_records AS r
INNER JOIN vehicles AS v USING (veh_reg_no)
INNER JOIN customers AS c USING (customer_id)
ORDER BY v.category, start_date;
13. Staff: Keeping track of staff serving the customers. Create a new staff table. Assume that each transaction is handled by one
staff, we can add a new column called staff_id in the rental_records table,
INSERT INTO staff VALUE (8001, 'Peter Johns', 'Managing Director', '1 Happy Ave', '12345678', 8001);
SELECT * FROM staff;
Advanced Exercises
1. Adding Photo: We could store photo in MySQL using data type of BLOB (Binary Large Object) (up to 64KB), MEDIUMBLOB (up to
16MBytes), LONGBOLB (up to 4GBytes). For example,
You can conveniently load and view the photo via graphical tools such as MySQL Workbench. To load a image in MySQL
Workbench ⇒ right-click on the cell ⇒ Load Value From File ⇒ Select the image file. To view the image ⇒ right-click on the BLOB
cell ⇒ Open Value in Editor ⇒ choose "Image" pane.
I also include a Java program for reading and writing image BLOB from/to the database, based on this example:
"TestImageBLOB.java".
2. VIEW: Create a VIEW called rental_prices on the rental_records with an additional column called price. Show all the
records of the VIEW.
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 37/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
INNER JOIN vehicles AS v USING (veh_reg_no)
INNER JOIN customers AS c USING (customer_id);
DESC `rental_prices`;
SHOW CREATE VIEW `rental_prices` \G
It is probably easier to compute the price using a program/procedure, instead of inside the view.
3. From the payments table, create a view to show the outstanding balance.
4. Define more views.
5. FUNCTION: Write a function to compute the rental price.
6. Define more procedures and functions.
7. TRIGGER: Write a trigger for the created_date and created_by columns of the payments table.
8. Define more triggers.
9. Implement discount on weekday (Monday to Friday, except public holiday): Need to set up a new table called public_hoilday
with columns date and description. Use function DAYOFWEEK (1=Sunday, …, 7=Saturday) to check for weekday or weekend.
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 38/39
23/11/2019 MySQL Tutorial - MySQL By Examples for Beginners
[TODO] Explanation
Feedback, comments, corrections, and errata can be sent to Chua Hock-Chuan (ehchua@ntu.edu.sg) | HOME
https://www.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html 39/39