Relational Databases SQL - TheDavSmasher/softwareconstruction GitHub Wiki

🖥️ Slides

🖥️ Lecture Videos

Structured Query Language (SQL) is a programming language that is specifically designed to interact with relational databases. It contains statements for inserting, updating, reading, and deleting data. It also provides statements for managing the database and the users that have access to the database.

You can categorizes the most commonly used SQL statements into the following buckets.

  1. DDL (Data Definition Language) - Create, alter, drop.
  2. DML (Data Manipulation Language) - Insert, update, delete.
  3. DQL (Data Query Language) - Select.

Here is an example of SQL statements for creating a database, creating at table, and inserting some sample data.

> CREATE DATABASE pet_store;
> USE pet_store;
> CREATE TABLE pet (id int, name varchar(255), type varchar(255));
> INSERT INTO pet VALUES (93, "Fido", "dog");
> INSERT INTO pet VALUES (14, "Puddles", "cat");
> INSERT INTO pet VALUES (77, "Chip", "bird");
> DESCRIBE pet;

+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | int          | YES  |     | NULL    |       |
| name  | varchar(255) | YES  |     | NULL    |       |
| type  | varchar(255) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+

The following demonstrates a simple query to read all of the pets in a database.

> SELECT id, name, type FROM pet;

+--------+----------+---------------+
| id     | name     | type          |
+--------+----------+---------------+
| 93     | Fido     | dog           |
| 14     | Puddles  | cat           |
| 77     | Chip     | bird          |
+--------+----------+---------------+

SQL is a declarative programming language. This means that you declare what you want rather than providing a series of imperative commands that define how to do something.

In order to completely understand the above example we need to take a step back and examine some of the common SQL statements.

Working with Databases

A database server, or remote database management system (RDBMS), can host one or more databases. You create a database with the CREATE DATABASE statement. After you have created the database you execute a USE statement to select the database for use with future commands.

CREATE DATABASE pet_store;
USE pet_store;

All databases have a default character set that is used for representing bytes as text. Normally if you would specify the character set when you execute the CREATE request, but if you didn't then you can alter the database with the ALTER DATABASE statement. For example, if you wanted to represent text with UTF-8, we would run the following ALTER statement.

ALTER DATABASE pet_store CHARACTER SET utf8mb4;

If you want to delete a database, and all of the data it represents, you use the DROP DATABASE statement. While this should rarely be used in a production environment, it is common to drop a database in a development environment while you are experimenting with creating working table schemas.

DROP DATABASE pet_store

Working with Tables

Now that you have a database you can create a table to hold the rows that represent your objects. Remember that a table is similar to declaring a Java class. When you create a table, you must specify each field and the type of the field.

CREATE TABLE pet (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    type VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

Notice that each field is followed by the NOT NULL clause. That means each of the fields must be provided for every row that is inserted.

The id field is also annotated with the AUTO_INCREMENT keyword. This means that you don't actually provide the id field when you insert a row. The database will do that for you using an automatically increasing integer.

Altering tables

If you need to alter your table you can use an ALTER TABLE statement. The following example shows you how to add a nickname field after the table is created. This alteration does not use the NOT NULL clause and so all of the existing nickname fields will be set to NULL. If a new row is added without specifying the nickname field, it will also be set to NULL.

ALTER TABLE pet ADD COLUMN nickname VARCHAR(255);

If you decide that you want to delete a table then you execute a DROP TABLE statement.

DROP TABLE pet;

Make sure you really want to drop the table before you execute the command, because there is no recovery from this one.

It is important to note that changing and rerunning a CREATE TABLE statement does not change an existing table. A CREATE TABLE statement only creates a table. If the table already exists this command will throw an error. You can use CREATE TABLE IF NOT EXISTS qualifier in order to not throw an error if it already exists, but if you want to change an existing table definition you must either drop the table and recreate it, or use an ALTER TABLE statement.

Primary Keys and Indexes

Along with specifying each field, the CREATE TABLE statement specifies which field is the primary key of the table. Primary keys are required to be unique. If you attempt to insert two rows with the same key, an error will occur. Primary keys are also indexed by default since it is assumed that you will use the key to query the table.

With an index on a field, the performance of your queries will significantly increase, but you also consume storage and memory for each index you allocate. That means you should only create indexes when you can demonstrate that it is necessary for performance reasons.

In addition to creating an index by specifying the primary key field, you can create indexes on other fields by specifying the INDEX keyword followed by the field you want to index. In the example below we added an index on the name field with the last clause in the statement.

CREATE TABLE pet (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    type VARCHAR(255) NOT NULL,
    PRIMARY KEY (id),
    INDEX (name)
);

If you determine you need an index after you create a table, you can use the CREATE INDEX statement along with the table and field you want to index.

CREATE INDEX index_name ON pet (name);

Types

Here is a list of the common SQL data types that you can use when you create a table.

Data type Description Example
INT Integer numbers. 1, 10, -100
DECIMAL Fixed-point decimal numbers. 1.23, 100.00, -5.6789
FLOAT Single-precision floating-point numbers. 1.23456789, 100.000000, -5.67890123
DOUBLE Double-precision floating-point numbers. 1.234567890123456, 100.00000000000000, -5.678901234567890
CHAR Fixed-length character strings. 'A', 'Hello, world!', '1234567890'
VARCHAR Variable-length character strings. 'A', 'Hello, world!', '1234567890'
TEXT Variable-length text data. 'This is a long text string that can be any length.'
BLOB Variable-length binary data. Binary data of any length
DATE Date values. '2023-10-14'
TIME Time values. '15:43:45'
DATETIME Date and time values. '2023-10-14 15:43:45'

Inserting, Updating, and Deleting Data

Now that you have a database and a table, it is time to insert some data. You can insert data into a table with an INSERT statement. This statement takes the name of the table, the fields you want to insert, and the values for those fields. If you created the fields with the NOT NULL annotation then you must supply all the non-null fields during the insertion.

INSERT INTO pet (name, type) VALUES ('Puddles', 'cat');

If you need to update an existing row then you use an UPDATE statement along with the names and values of the fields you want to update. When updating a row you want to be careful to specify which rows to update with a WHERE clause. If you don't specify which rows to update, then all the rows will be updated. In the example below, only the row with an id equal to 1 will be updated to set the pet name to fido.

UPDATE pet SET name = 'fido' WHERE id = 1;

When you want to delete some rows, you use a DELETE statement and specify a WHERE clause to select the rows to delete. The following will delete all rows where the pet is a cat.

DELETE FROM pet WHERE type = 'cat';

If you want to delete all data from a table, then use the TRUNCATE statement. This will delete all of the table's data, but not the table itself.

TRUNCATE TABLE pet;

Selecting Data

The SELECT statement provides the primary mechanism for querying data from a SQL compliant RDBMS. Here is an example of a simple SELECT that returns all the names and types for every pet.

SELECT name, type FROM pet;

If you want to select specific pets, then you include a WHERE clause. WHERE clauses can be very complex. They can include boolean predicates, wildcards. You can also supply a LIMIT on the amount of data to return. Here is an example of a SELECT that returns a maximum of two rows that are either dogs with any name, or cats named Puddle.

SELECT name, type FROM pet WHERE type='dog' OR (type='cat' AND name='Puddle') LIMIT 2;

You can select all rows in a table with the * query. You can also use the COUNT predicate to tell you how many rows there are in a table.

SELECT * from pet;
SELECT COUNT(0) from pet;

Joining Tables

If you want to combine tables to compute a temporary different view of the data then you would use a JOIN clause along with the names of the two tables that you want to join. The following example would join together the purchase and pet tables into rows with matching pet IDs.

SELECT purchase.id AS purchaseId, purchase.ownerId, pet.id AS petId, pet.name, pet.type
 FROM purchase JOIN pet WHERE purchase.petId = pet.id;

Given the following source tables,

Source

+----+-------+---------+
| id | petId | ownerId |
+----+-------+---------+
|  1 |   890 |       3 |
|  2 |   891 |       3 |
|  3 |   895 |       4 |
+----+-------+---------+

+-----+---------+------+----------+
| id  | name    | type | nickname |
+-----+---------+------+----------+
| 890 | Puddles | cat  | NULL     |
| 891 | Fluffy  | cat  | NULL     |
| 892 | Willie  | cat  | NULL     |
| 893 | George  | bird | NULL     |
| 894 | Buddy   | dog  | NULL     |
| 895 | Fido    | dog  | NULL     |
+-----+---------+------+----------+

this would be the result of our JOIN SELECT statement.

Result

+------------+---------+-------+---------+------+
| purchaseId | ownerId | petId | name    | type |
+------------+---------+-------+---------+------+
|          1 |       3 |   890 | Puddles | cat  |
|          2 |       3 |   891 | Fluffy  | cat  |
|          3 |       4 |   895 | Fido    | dog  |
+------------+---------+-------+---------+------+

Initializing Your Database

When you are using a database to store your application data, it is often useful to make sure all of your databases and tables exist when you start up. You can do this by executing CREATE DATABASE and CREATE TABLE calls at the beginning of your application. You can conditionally create these objects with the IF NOT EXISTS clause. With that clause, the statement is simply ignored if the structure already exists.

CREATE DATABASE IF NOT EXISTS petshop;
USE petshop;
CREATE TABLE  IF NOT EXISTS pet (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    type VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

By following this pattern, your application will always work even when it starts up using a database server that has not yet been initialized. This pattern is called infrastructure as code because it treats your configuration as code, removes the human error factor, and tracks the history of the infrastructure changes with the same version control process that your code uses.

When we discuss the Java Database Connector (JDBC) we will demonstrate how to initialize your database from your Java code.

You can also write a text file that contains SQL statements and execute them using the MySQL client shell (mysqlsh). For example, while you are trying to figure out what you want your final database schema to look like, you could use an initialization SQL script that deletes the database, recreates it, and creates all of the tables.

DROP DATABASE pet_store;
CREATE DATABASE pet_store;

USE pet_store;

CREATE TABLE pet (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    type VARCHAR(255) NOT NULL,
    PRIMARY KEY (id),
    INDEX (name)
);

You could run the script with the following console command.

➜ mysqlsh -u yourusername -pyourpassword --sql < initialize.sql

Table of Common SQL Commands

The follow table summaries all of the commands that were used in this instruction topic.

Command Purpose Example statement
CREATE DATABASE Creates a new database. CREATE DATABASE pet_store;
ALTER DATABASE Modifies the structure of a database. ALTER DATABASE pet_store CHARACTER SET utf8mb4;
DROP DATABASE Deletes a database. DROP DATABASE pet_store;
USE DATABASE Selects a database for use with future commands. USE pet_store;
CREATE TABLE Creates a new table in a database. CREATE TABLE pet (id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY (id));
DESCRIBE TABLE Describes the fields in a table. DESCRIBE pet;
ALTER TABLE Modifies the structure of a table. ALTER TABLE pet ADD COLUMN nickname VARCHAR(255);
DROP TABLE Deletes a table from a database. DROP TABLE pet;
INSERT INTO Inserts new data into a table. INSERT INTO pet (name, type) VALUES ('Puddles', 'cat');
SELECT Select data from a table. SELECT name, type FROM pet;
UPDATE Updates existing data in a table. UPDATE pet SET name = 'fido' WHERE id = 1;
DELETE Deletes data from a table. DELETE FROM pet WHERE id = 1;
CREATE INDEX Creates an index on a column or columns in a table. CREATE INDEX pet_name_index ON pet (name);
DROP INDEX Deletes an index from a table. DROP INDEX pet_name_index;
TRUNCATE TABLE Deletes all rows from a table, but preserves the table structure. TRUNCATE TABLE pet;
CREATE VIEW Creates a virtual table that is based on one or more underlying tables. CREATE VIEW cats AS SELECT * FROM pet WHERE type = 'cat';
DROP VIEW Deletes a view. DROP VIEW cats;

Things to Understand

  • How to create and drop tables
  • Why drop table if exists is useful
  • How to insert, update, delete, and retrieve data from a database table
  • How to retrieve data from multiple related tables using a join
  • What database transactions are and why we need them

Videos (42:05)

Demonstration code

📁 Book.java

📁 DatabaseAccessExample.java

📁 create-db.sql.txt

⚠️ **GitHub.com Fallback** ⚠️