mirror of
https://github.com/opsschool/curriculum.git
synced 2025-12-06 00:19:45 +01:00
489 lines
15 KiB
ReStructuredText
489 lines
15 KiB
ReStructuredText
Databases 101 (Relational Databases)
|
||
************************************
|
||
|
||
What is a Database?
|
||
===================
|
||
|
||
A database is a program or library that helps you store data.
|
||
They usually impose some sort of structure to the data to assist with querying and filtering.
|
||
The most common structure databases use to store data is a table, and most databases will use multiple tables to store data.
|
||
|
||
A table is composed of rows representing an item, and columns represent some attribute of that item.
|
||
Much like using a spreadsheet for a task list, where a row would be a task, and you may have a column for a task name, and a second column to determine whether it has been completed.
|
||
|
||
What is a Relational Database?
|
||
==============================
|
||
|
||
A relational database is a database in which data is organized into tables, usually with some form of relationship between them.
|
||
For example, a table containing customer names and addresses, and a table containing sales transactions.
|
||
Rather than repeat customer details every time a transaction is done, the data is stored once in one table, and then a unique reference is stored in the sales transactions table, linking each transaction to the customer.
|
||
This approach makes a relational database very efficient for storing data, since reused data can be stored in a single table and referenced in other tables.
|
||
|
||
Data can be retrieved in many forms by combining multiple tables into new tables using operations like ``JOIN``.
|
||
The composed table will have new rows that are a combination of its parent tables.
|
||
|
||
Why We Use Databases?
|
||
=====================
|
||
|
||
We use databases to store data.
|
||
They help provide us guarantees that data is stored and that it exists in the correct format.
|
||
In addition most databases are heavily optimized making data retrieval very fast.
|
||
|
||
Because of these attributes, we use databases a lot.
|
||
Most e-commerce sites use databases to keep inventory and sales records.
|
||
Doctors offices use databases to store medical records, and the DMV uses databases to keep track of cars.
|
||
Lawyers use databases to keep track of case law, and many websites use databases to store and organize content.
|
||
Databases are everywhere, and you interact with them daily.
|
||
|
||
What is SQL?
|
||
============
|
||
|
||
SQL or Structured Query Language is a :term:`domain specific language` used for accessing databases.
|
||
It has a declarative syntax, meaning you declare the structure you want returned, the sources, and constraints in a single statement.
|
||
The database's query parser and planner will determine a how to retrieve your data from this statement.
|
||
|
||
SQL shell
|
||
=========
|
||
|
||
Many relational databases provide an interactive :term:`CLI` for interacting with the database.
|
||
For example, MySQL provides the ``mysql`` command, Postgresql provides ``psql``, and Oracle provides ``sqlplus``.
|
||
These programs give you the ability to compose queries, and diagnose issues with the software.
|
||
|
||
todo:: Add example of connecting with each command.
|
||
|
||
MySQL
|
||
-----
|
||
|
||
To connect to a MySQL database from the CLI your command would usually take this form:
|
||
|
||
.. code-block:: console
|
||
|
||
$ mysql -u username -p -h server-address
|
||
Password:
|
||
|
||
Of these flags, ``-u`` = username, ``-p`` = password, and ``-h`` = hostname.
|
||
You may provide the password on the command prompt: ``-ppassword`` (no space after flag!).
|
||
We strongly advise against this, as this may leave the password visible in your shell history.
|
||
|
||
Creating databases
|
||
==================
|
||
|
||
Most database platforms allow you to create a new database using the ``CREATE DATABASE`` SQL query.
|
||
It can be executed via a connection to the server, or via the SQL shell.
|
||
|
||
A MySQL example:
|
||
|
||
.. code-block:: sql
|
||
|
||
mysql> CREATE DATABASE example_database;
|
||
|
||
|
||
Specialized Create Database Commands
|
||
------------------------------------
|
||
|
||
Some database platforms have specialized :term:`GUI` tools, or CLI tools.
|
||
For example Postgresql has a UNIX command ``createdb`` that creates databases.
|
||
In many cases these commands are just wrappers around the standard SQL statements.
|
||
|
||
MySQL
|
||
~~~~~
|
||
|
||
.. code-block:: console
|
||
|
||
$ mysqladmin create example_database
|
||
|
||
|
||
Postgresql
|
||
~~~~~~~~~~
|
||
|
||
.. code-block:: console
|
||
|
||
$ createdb example_database
|
||
|
||
Some platforms, like MySQL support multiple databases per instance, while other platforms like Oracle support one database per instance.
|
||
You should check the documentation for your particular vendor to see what is supported.
|
||
|
||
Creating users
|
||
==============
|
||
|
||
Users can be created in most databases using the the ``CREATE USER`` statement.
|
||
|
||
.. code-block:: sql
|
||
|
||
mysql> CREATE USER username;
|
||
|
||
|
||
Specialized Create User Commands
|
||
--------------------------------
|
||
|
||
Some relational databases provide additional ways of creating users like specialized command line programs.
|
||
|
||
MySQL
|
||
~~~~~
|
||
|
||
MySQL does not support creation of users via the ``mysqladmin`` command.
|
||
|
||
Postgresql
|
||
~~~~~~~~~~
|
||
|
||
.. code-block:: console
|
||
|
||
$ createuser username
|
||
|
||
Create Tables
|
||
=============
|
||
Tables are organized into rows and columns.
|
||
Data is stored inside these tables.
|
||
In order to host this information we need to create a table.
|
||
We do this with the ``CREATE TABLE`` statement.
|
||
|
||
Standard Syntax is:
|
||
|
||
.. code-block:: sql
|
||
|
||
CREATE TABLE table_name (
|
||
column1 datatype(size),
|
||
column2 datatype(size),
|
||
column3 datatype(size)
|
||
);
|
||
|
||
Here is an example.
|
||
This will create a table called "Users" with 2 columns.
|
||
|
||
.. code-block:: sql
|
||
|
||
CREATE TABLE Users (
|
||
name varchar(50),
|
||
address varchar(50)
|
||
);
|
||
|
||
Alter Table
|
||
===========
|
||
|
||
The ``ALTER`` statement will allow you to modify the design of your current database.
|
||
For example, if you have a table called "Users" which contains Names and Addresses, but you need need to add an age column, you could do so with:
|
||
|
||
.. code-block:: sql
|
||
|
||
ALTER TABLE Users ADD age int;
|
||
|
||
Standard Syntax is:
|
||
|
||
.. code-block:: sql
|
||
|
||
ALTER TABLE table_name ADD column_name datatype
|
||
|
||
If we need to modify a current table, we can also do so with the ``ALTER`` statement.
|
||
If in the previous example you wanted to change the datatype of age from an integer to varchar, you would do so with:
|
||
|
||
.. code-block:: sql
|
||
|
||
ALTER TABLE Users MODIFY age varchar(50);
|
||
|
||
Standard Syntax is:
|
||
|
||
.. code-block:: sql
|
||
|
||
ALTER TABLE table_name MODIFY column_name datatype
|
||
|
||
If you now realize you don't need the age column at all, you can drop it all together with:
|
||
|
||
.. code-block:: sql
|
||
|
||
ALTER TABLE Users DROP age;
|
||
|
||
Standard Syntax is:
|
||
|
||
.. code-block:: sql
|
||
|
||
ALTER TABLE table_name DROP column_name
|
||
|
||
Drop Table
|
||
===========
|
||
|
||
If you have created a table and need to remove it from your database, you can with the ``DROP`` statement:
|
||
|
||
Standard Syntax is:
|
||
|
||
.. code-block:: sql
|
||
|
||
DROP table table_name
|
||
|
||
If we want to drop our table we created earlier (Users) we would use this command:
|
||
|
||
.. code-block:: sql
|
||
|
||
DROP table Users;
|
||
|
||
Data Type
|
||
===========
|
||
|
||
There are different types of data that we will store in our database.
|
||
It can be simple text or a number, sometimes it is a mix of these things.
|
||
The table below lists some common Standard SQL commands that are also in MySQL.
|
||
It is important to note this is not a complete list.
|
||
|
||
========== ==================================================================================================
|
||
Data type Description
|
||
========== ==================================================================================================
|
||
char(n) Fixed width character string, can hold letters and numbers-Max of 8,000 characters
|
||
varchar(n) Variable width character string, can hold letters and numbers- Max of 8,000 characters
|
||
text Variable width character string. Value is represented internally by a separately allocated object
|
||
int Allows whole numbers between -2,147,483,648 and 2,147,483,647
|
||
float A small number with a floating decimal point
|
||
decimal An exact numeric data value, allowing for a fixed decimal point
|
||
date Date formated as YYYY-MM-DD
|
||
datetime Date and time combination formated as YYYY-MM-DD HH:MM:SS
|
||
timestamp Stores a unique number that gets updated every time a row gets created or modified
|
||
========== ==================================================================================================
|
||
|
||
|
||
Granting privileges
|
||
===================
|
||
|
||
Privileges can be granted using the SQL GRANT statement. These
|
||
statements are persisted by the RDBMS when issued. The typical
|
||
command format is:
|
||
|
||
.. code-block:: sql
|
||
|
||
GRANT [PRIVILEGE] on [OBJECT] to [USER];
|
||
|
||
The standard SQL privileges are:
|
||
|
||
========== ====================================================
|
||
Privilege Description
|
||
========== ====================================================
|
||
ALL Allows user all privileges
|
||
ALTER Allows user to alter schema objects
|
||
CREATE Allows user to create schema object like tables
|
||
DELETE Allows user to delete from an object
|
||
EXECUTE Allows user to execute a store procedure or function
|
||
INSERT Allows user to add new data to an object
|
||
REFERENCES Allows user to create a referential table constraint
|
||
SELECT Allows user to read from an object
|
||
TRIGGER Allows user to create a trigger
|
||
TEMPORARY Allows user to create temporary tables
|
||
UPDATE Allows user to update existing data in an object
|
||
========== ====================================================
|
||
|
||
Below is an example granting a user SELECT privileges on a table
|
||
|
||
.. code-block:: sql
|
||
|
||
GRANT SELECT ON TABLE example_table TO user;
|
||
|
||
You can also grant multiple privileges in a single statement.
|
||
|
||
.. code-block:: sql
|
||
|
||
GRANT SELECT,INSERT ON TABLE example_table TO user;
|
||
|
||
Many databases stray from the SQL standard here, and it is important to read your database's documentation when granting privileges.
|
||
There may be additional privileges not listed here and syntax can vary significantly.
|
||
|
||
Removing Privileges
|
||
===================
|
||
|
||
Privileges are removed with the SQL ``REVOKE`` statement.
|
||
It follows a similar command format like grant:
|
||
|
||
.. code-block:: sql
|
||
|
||
REVOKE [PRIVILEGE] on [OBJECT] FROM [USER];
|
||
|
||
|
||
Basic normalized schema design
|
||
==============================
|
||
|
||
A normalized schema is a database with a table and column structure designed to reduce data redundancy.
|
||
Typically data is placed into tables with a unique identifier, or primary key, and then is referenced by id in any tables that wish to use that data.
|
||
|
||
Suppose we have two types of records in a database; one for a city's population
|
||
and one for a city's average temperature.
|
||
We could simply create the tables like so:
|
||
|
||
City Population:
|
||
|
||
============= ==========
|
||
City Population
|
||
============= ==========
|
||
San Francisco 812,826
|
||
============= ==========
|
||
|
||
City Temperature:
|
||
|
||
============= ===========
|
||
City Temperature
|
||
============= ===========
|
||
San Francisco 73 F
|
||
============= ===========
|
||
|
||
A normalized version of this would have three tables instead of two.
|
||
|
||
City ID and Name:
|
||
|
||
============= =============
|
||
City_id Name
|
||
============= =============
|
||
1 San Francisco
|
||
============= =============
|
||
|
||
City ID and Temperature:
|
||
|
||
============= ===========
|
||
City_id Temperature
|
||
============= ===========
|
||
1 73 F
|
||
============= ===========
|
||
|
||
City ID and Population:
|
||
|
||
============= ==========
|
||
City_id Population
|
||
============= ==========
|
||
1 812,826
|
||
============= ==========
|
||
|
||
The advantage of this design is that it prevents you from having to enter data multiple times, and generally reduces the storage cost of a row.
|
||
If San Francisco changed its name you would only need to update a single row instead of two tables like the first example.
|
||
SQL allows you to replace the ``id`` with a name using a ``JOIN`` statement
|
||
when the data is retrieved, making it functionally identical to the two table example.
|
||
|
||
Select, Insert, Update and Delete
|
||
=================================
|
||
|
||
SELECT
|
||
------
|
||
|
||
The ``SELECT`` statement is the standard way you read from a table in an SQL database.
|
||
You can use it to retrieve a set of data, and perform aggregations on them.
|
||
The standard syntax is:
|
||
|
||
.. code-block:: sql
|
||
|
||
SELECT [column1,column2|*] FROM [TABLE];
|
||
|
||
By adding a ``WHERE`` statement, you can have the database filter results:
|
||
|
||
.. code-block:: sql
|
||
|
||
SELECT user_id, user_name FROM users WHERE user_id = 1;
|
||
|
||
You can join tables using a ``JOIN`` statement.
|
||
In this example we're temporarily assigning an alias of 'u' for the table users and an alias of 'a' for the table addresses:
|
||
|
||
.. code-block:: sql
|
||
|
||
SELECT user_id, user_name FROM users u JOIN addresses a
|
||
ON u.user_id = a.user_id WHERE user_id = 1;
|
||
|
||
Count the rows in a table by using an aggregation:
|
||
|
||
.. code-block:: sql
|
||
|
||
SELECT COUNT(1) FROM users;
|
||
|
||
Order by a column:
|
||
|
||
.. code-block:: sql
|
||
|
||
SELECT * FROM users ORDER BY user_name;
|
||
|
||
INSERT
|
||
------
|
||
|
||
The ``INSERT`` statement is used to add additional data into a table.
|
||
It can be used to insert data either a row at a time or in bulk.
|
||
The standard syntax is:
|
||
|
||
.. code-block:: sql
|
||
|
||
INSERT INTO table (column1, column2, column3) VALUES (value1, value2, value2)
|
||
|
||
The column list is optional, if you don’t specify which columns you’re inserting data into, you must provide data for all columns.
|
||
|
||
For example, to insert a single row:
|
||
|
||
.. code-block:: sql
|
||
|
||
INSERT INTO users (user_name,user_phone) VALUES ("Joe Bloggs","555-1234");
|
||
|
||
Or in bulk:
|
||
|
||
.. code-block:: sql
|
||
|
||
INSERT INTO users (user_name,user_phone)
|
||
VALUES ("John Smith","555-5555"),("Tom Jones","555-0987");
|
||
|
||
Inserting in bulk like that is typically much quicker than using separate queries as the query planner only has to execute once, and any indexes are updated at the end.
|
||
|
||
|
||
UPDATE
|
||
------
|
||
|
||
``UPDATE`` is the SQL statement for updating existing data in a table.
|
||
It should almost always be used with a conditional statement.
|
||
The standard syntax is:
|
||
|
||
.. code-block:: none
|
||
|
||
UPDATE [TABLE] SET [COLUMN] = {expression}, {COLUMN2={expression}, ...}
|
||
[WHERE condition]
|
||
[ORDER BY ...]
|
||
[LIMIT count];
|
||
|
||
Without a ``WHERE`` condition, the statement will apply to all the rows in a table.
|
||
|
||
Here is a simple example of an ``UPDATE`` statement:
|
||
|
||
.. code-block:: sql
|
||
|
||
UPDATE users SET user_name = 'Jim Smith' WHERE user_name = 'James Smith';
|
||
|
||
|
||
DELETE
|
||
------
|
||
|
||
``DELETE`` is the SQL statement for removing rows from a table.
|
||
The standard syntax is:
|
||
|
||
.. code-block:: sql
|
||
|
||
DELETE FROM [TABLE]
|
||
[WHERE condition]
|
||
[ORDER BY ...]
|
||
[LIMIT count] ;
|
||
|
||
.. note:: Without a ``WHERE`` condition the statement will apply to **all** the rows of a table.
|
||
|
||
Here is a simple example of a DELETE statement:
|
||
|
||
.. code-block:: sql
|
||
|
||
DELETE FROM users WHERE user_name = 'James Smith';
|
||
|
||
|
||
Pro Tips
|
||
========
|
||
|
||
- Before doing a write query, run it as a read query first to make sure you are retrieveing exactly what you want.
|
||
If your query is:
|
||
|
||
``UPDATE users SET disabled=1 WHERE id=1;``
|
||
|
||
Run this first to validate you will be affecting the proper record:
|
||
|
||
``SELECT disabled FROM users WHERE id=1;``
|
||
|
||
- use a ``LIMIT`` on ``UPDATE`` and ``DELETE FROM`` queries to limit damage imposed by an erroneous query
|
||
|
||
``UPDATE users SET disabled=1 WHERE id=1 LIMIT 1;``
|
||
|
||
``DELETE FROM users WHERE id=1 LIMIT 1;``
|
||
|
||
- If your database supports transactions, run ``START TRANSACTION`` first then run your query and check what it has done.
|
||
If you're happy with what you see then run ``COMMIT`` and finally ``STOP TRANSACTION``.
|
||
If you realize you've made a mistake, you can run ``ROLLBACK`` and any changes you've made will be
|
||
undone.
|