Beginner SQL Tutorial

Andrew Bliss
4 min readApr 2, 2019

SQL (pronounced “ess-que-el”) stands for Structured Query Language.
SQL commands are used to communicate with a database. Databases are a
collection of tables that store client information. A client could
have data stored about their account, users, transactions, and we
could write SQL queries to ask certain questions about their data.
Such as, how many new users do I have this month, what is my burn,
churn rate versus my new growth?

So let’s lay the groundwork so that we can start asking these queries.

  1. Plan out our queries
  2. Install the database service
  3. Create the database and schema
  4. Seed the database with test accounts
  5. Learn basic SQL commands
  6. Write our first query

Plan out our queries

For our database we want accounts, users, and a transactions table.

  1. Basic-Show me all accounts
  2. Advanced-Show me users by month per account

Install the database service

We will be using docker to create our database service so we can build
our data structures and start storing the data needed to ask our
questions.

Go to this link to install docker for windows.

https://docs.docker.com/docker-for-windows/install/

Create a docker-compose.yml file.

version: ‘3’
services:
postgres:
image: postgres
ports:
— “5432:5432”
env_file:
— .env
volumes:
— ./sql:/sql
— postgres-data:/var/lib/postgresql/data
restart: always
volumes:
postgres-data:

Create an environment file .env

POSTGRES_HOST=postgres
POSTGRES_DB=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_PORT=5432

Start the services by running the following command:

docker-compose up

Create the database and schema

Create a file called ./sql/init.sql. We will define our tables to
store our data.

CREATE TABLE IF NOT EXISTS accounts (
id SERIAL,
name VARCHAR(255),
“createdAt” DATE,
“updatedAt” DATE,
“deletedAt” DATE,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS users (
id SERIAL,
“accountId” INTEGER REFERENCES accounts(id) ON DELETE CASCADE ON
UPDATE CASCADE,
“firstName” VARCHAR(255),
“lastName” VARCHAR(255),
“createdAt” TIMESTAMP,
“updatedAt” TIMESTAMP,
“deletedAt” TIMESTAMP,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS transactions (
id SERIAL,
“accountId” INTEGER REFERENCES accounts(id) ON DELETE CASCADE ON
UPDATE CASCADE,
“userId” INTEGER REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,
“amount” FLOAT,
“createdAt” TIMESTAMP,
“updatedAt” TIMESTAMP,
“deletedAt” TIMESTAMP,
PRIMARY KEY (id)
);

Now run the command through docker

docker exec -it sql_postgres_1 psql -U postgres -f ./sql/init.sql

Seed the database with test accounts

Create a file called ./sql/seed.sql

INSERT INTO accounts (name, “createdAt”, “updatedAt”) VALUES
(‘NodeJs’, ‘2019–01–01’, ‘2019–01–01’),
(‘Postgres’, ‘2019–02–01’, ‘2019–01–01’),
(‘MySQL’, ‘2019–03–01’, ‘2019–01–01’),
(‘Oracle’, ‘2019–03–01’, ‘2019–01–01’),
(‘Jave’, ‘2019–04–01’, ‘2019–01–01’),
(‘PHP’, ‘2019–05–01’, ‘2019–01–01’),
(‘Docker’, ‘2019–05–01’, ‘2019–01–01’),
(‘Gitlab’, ‘2019–05–01’, ‘2019–01–01’),
(‘Zoho’, ‘2019–05–01’, ‘2019–01–01’),
(‘Quickbooks’, ‘2019–06–01’, ‘2019–01–01’);
INSERT INTO users (“accountId”, “firstName”, “lastName”, “createdAt”,
“updatedAt”) VALUES
(1, ‘John’, ‘Johnson’, ‘2019–01–01’, ‘2019–11–01’),
(1, ‘Jack’, ‘Johnson’, ‘2019–02–01’, ‘2019–10–01’),
(2, ‘Rob’, ‘Johnson’, ‘2019–02–01’, ‘2019–05–01’),
(2, ‘Robby’, ‘Johnson’, ‘2019–02–01’, ‘2019–06–01’),
(2, ‘Mac’, ‘Johnson’, ‘2019–03–01’, ‘2019–05–01’),
(3, ‘Michael’, ‘Johnson’, ‘2019–03–01’, ‘2019–04–01’),
(4, ‘Mock’, ‘Johnson’, ‘2019–04–01’, ‘2019–02–01’),
(4, ‘Fib’, ‘Johnson’, ‘2019–04–01’, ‘2019–10–01’),
(5, ‘Kal’, ‘Johnson’, ‘2019–04–01’, ‘2019–12–01’),
(6, ‘Mil’, ‘Johnson’, ‘2019–05–01’, ‘2019–11–01’),
(7, ‘Stohn’, ‘Johnson’, ‘2019–06–01’, ‘2019–04–01’),
(8, ‘Jock’, ‘Johnson’, ‘2019–07–01’, ‘2019–02–01’),
(9, ‘Sack’, ‘Johnson’, ‘2019–08–01’, ‘2019–03–01’),(9, ‘Pack’,
‘Johnson’, ‘2019–09–01’, ‘2019–04–01’);
INSERT INTO transactions (“accountId”, “userId”, “amount”,
“createdAt”, “updatedAt”) VALUES
(1, 1, 106.01, ‘2019–01–01’, ‘2019–11–01’),
(1, 2, 98.01, ‘2019–02–01’, ‘2019–10–01’),
(2, 3, 56.01, ‘2019–02–01’, ‘2019–05–01’),
(2, 4, 10.01, ‘2019–02–01’, ‘2019–06–01’),
(2, 4, 23.01, ‘2019–03–01’, ‘2019–05–01’),
(3, 6, 78.01, ‘2019–03–01’, ‘2019–04–01’),
(4, 7, 10.01, ‘2019–04–01’, ‘2019–02–01’),
(4, 8, 45.01, ‘2019–04–01’, ‘2019–10–01’),
(5, 9, 56.01, ‘2019–04–01’, ‘2019–12–01’),
(6, 10, 78.01, ‘2019–05–01’, ‘2019–11–01’),
(7, 11, 45.01, ‘2019–06–01’, ‘2019–04–01’),
(8, 12, 456.01, ‘2019–07–01’, ‘2019–02–01’),
(9, 13, 67.01, ‘2019–08–01’, ‘2019–03–01’),
(9, 13, 45.01, ‘2019–09–01’, ‘2019–04–01’);

Now run the command through docker

docker exec -it sql_postgres_1 psql -U postgres -f ./sql/seed.sql

Learn basic SQL commands

Now that we have laid the groundwork for our database we can start
asking it some basic questions.

To be able to retrieve that data we want back out of the database we
can give the database commands known as SQL.

To begin we will start with our first question. Show me all the accounts.

SELECT * FROM accounts;

The keyword SELECT is telling the database what columns we want to
return. The * says that we want all the columns. The keyword FROM says
that whatever comes after is the table we will pull data from. The
identifier accounts is saying what table we want to pull from.

Create a file called ./sql/all-accounts.sql

SELECT * FROM accounts;

To run this command run the following docker command

docker exec -it sql_postgres_1 psql -U postgres -f ./sql/all-accounts.sql

Let’s modify this example to include an aggregation function.

SELECT COUNT(*) FROM accounts;

Now instead of all the data returning back we just get a number of how
many rows it counted.

Now let’s create a file called ./sql/new-users-by-month.sql

SELECT
a.name as “accountName”,
to_char(u.”createdAt”, ‘YYYY-MM’) as “date”,
COUNT(u.id) as “newUserCount”
FROM users u
INNER JOIN accounts a ON a.id = u.”accountId”
GROUP BY a.id, to_char(u.”createdAt”, ‘YYYY-MM’);

We want to select the account name, the month / year when the user was
created, and a count of how many users were created in that month.

In order to get the account name we must write an INNER JOIN and join
the account “id” column to the users “accountId” column. This will
ensure the correct user is connected to the correct account.

Then we finally write a GROUP BY and group all the data by account id,
and year and month. Doing this is will correctly show in the COUNT
function how many new users were created.

To run this query run this command:

docker exec -it sql_postgres_1 psql -U postgres -f ./sql/new-users-by-month.sql

Conclusion

We have created our database services, seeded with data and ready to
write queries.

We learned some basic SQL keywords such as SELECT, FROM, COUNT, GROUP BY.

We learned how to run our services with docker and how to run SQL files.

Next in the intermediate SQL tutorial we will learn more about
conditions and joins.

--

--