SQL#
SQL, or Structured Query Language, is the language we use to "speak" to a database. We use SQL to query for data, insert data, delete data, organise and sort data, and more, inside of a relational database.
We're going to learn some basic SQL commands and use them to create a database inside of the SQLite database we created in the last section.
For reference, here's a complete list of the commands we're going to explore:
Command | Description |
---|---|
CREATE DATABASE | Allows us to create a database |
CREATE TABLE | Creates a table inside of a database |
INSERT | Adds data to a table |
UPDATE | Updates existing data in a table |
DELETE | Deletes existing data from a table |
SELECT | Queries the data inside of a database |
LIMIT | Restrict the number of results returned from a query |
WHERE | Allows us to refine what data we search for |
LIKE | Like WHERE , allows us to refine a query |
IN | Use IN in the same manner as LIKE , but with different values |
ORDER BY | Change the order data is presented in the search results |
ALTER TABLE | Updates the schema of a table |
DROP TABLE | Deletes a table from the database |
DROP DATABASE | Deletes a database |
Creating a database#
In SQLite, you create the database by opening the file: sqlite my_first.db
. In MySQL, PSQL, SQL Server, etc., you create the database using the CREATE DATABASE
statement.
I cannot go into too much detail here because the syntax for these command changes based on the engine you're using. That, and we don't need to use the statement because SQLite created the database for us.
Here's the syntax of CREATE DATABASE
for MySQL, PostgreSQL and SQL Server:
1 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
1 2 3 4 5 6 7 8 9 10 |
|
As you can see, the syntax can be really simple or more complicated, depending on the engine. You'll have to search for the "create database" syntax for the engine you're working with (in the future.)
Creating a table#
SQLite's CREATE TABLE
syntax is as follows:
1 2 3 4 5 6 7 |
|
We'll just create one table to work with for now. Copy and paste this SQL into the SQLite prompt you have open for my_first.db
:
1 2 3 4 5 6 7 |
|
And then use .tables
to see what you have:
1 2 3 4 5 6 7 8 9 |
|
Let's break down the command:
1 2 3 4 5 6 7 |
|
You'll notice all the documentation, and even as I write this chapter, the SQL is in UPPER CASE
? Like CREATE TABLE
? Yet my SQL, above, is not? It's actually not that important, but some people prefer to use upper case to keep it consistent with documentation. Either or works.
We called the table people
. Simple enough to understand. That's how we'll refer to this particular table (relationship) of data when we use other commands like SELECT
.
We created a schema made up of five columns: id
, name
, email
, age
, and gender
.
For the id
column we set the data type to integer
and we made this one column the primary key
. We could have included other columns in the primary key, but we're just learning here.
The name
, email
, and gender
columns all have a data type of text
, meaning they store text data like strings. The gender
column is the only column that does not have a not null
constraint against it, which means it's optional. The email
column has to be unique because emails are, by definition, unique.
We can look at this schema in SQLite: .schema people
1 2 3 4 5 6 7 8 |
|
This allows us to reference the schema later on should we need to.
Adding data#
Now that we have a table, let's insert some people into it!
1 2 3 4 5 6 |
|
This will add a new row to the table people
:
1 2 |
|
Note
We cover SELECT
next.
I've also done something interesting the above SQL. A few things actually.
Firstly, it's all in UPPER CASE
to simply prove a point: either or is fine. Pick which you prefer.
And lastly I've included a comment in my SQL in the form of -- LOL!
. Any text that being with --
in a SQLite SQL statement is considered a comment and is ignored. I've included this comment because my age being 21
is laughable!
Let's try inserting the exact same information again:
1 2 3 4 5 6 7 |
|
So our UNIQUE
constraint is working as expected on the email
column.
You'll notice I also included the gender
column when I didn't need to. Let's add a second person:
1 2 3 4 5 |
|
This command executes successfully: select * from people;
1 2 3 |
|
No gender
column (or value) is present for the second entry, which can be identified by its unique PRIMARY KEY
of 2
.
Updating records#
Our imposter's age is wrong (I knew it!) so we'll need to update that record:
1 |
|
Which gives us the desired results:
1 2 3 4 |
|
With an UPDATE
, we're defining what we want to update with set column = value
and we are using the WHERE
"clause" to only update the rows that have an id
of 2
. There will only be one of them as the id
column is unique for every row.
Micro project: use the UPDATE
command to change the gender
of id = 2
to be fluid
. I've already done this myself.
Deleting a record#
We've detected that our "imposter" is in fact, an imposter! We must delete their record from our database otherwise other people might think they're part of the cool team (our team.)
Let's do this using the DELETE
command:
1 |
|
This gets me:
1 2 3 |
|
Now our imposter has gone! We can also DELETE
records based on any column we like:
1 2 3 |
|
You can even combine them, too. SQL is an extremely powerful language and we're only doing the basics here.
Mass insert#
Before we move onto using SELECT
and other commands, let's do a mass insert of records so we've got plenty to work with. Copy and pasting the following:
1 2 3 4 5 6 |
|
This is just a big mass insert of a few records we can use in the next section.
Querying for records#
We have a table we can insert records int, edit them and even delete them. Now we now to be able to retrieve the data from the table using a query.
Let's query for every record: select * from people;
1 2 3 4 5 6 7 |
|
There are the records we added into the table earlier, but the output isn't very readable. Let's change that:
1 2 |
|
These options make a big difference:
1 2 3 4 5 6 7 8 9 |
|
That's all the records and columns. In our SELECT
statement we used *
inside the column selection part of the query. We can refine the columns we get back from the database by providing column names instead of *
: select name, email, age from people;
1 2 3 4 5 6 7 8 9 |
|
Now we only get the columns we've asked for.
Limiting the results#
We've got a total of: select count(*) from people;
records:
1 2 3 4 |
|
Note
Do some research on the count()
function in SQLite.
What if we only ever want three records returned by our queries? We can use LIMIT
to do this: select * from people limit 3;
1 2 3 4 5 6 |
|
That's simple enough to understand.
Refining our queries#
What if we want to restrict the results we get back to only ones that have specific characteristics? For example, what if we want to know who is younger than 30
years old? Let's try a WHERE
clause: select * from people where age < 30;
1 2 3 4 5 6 7 |
|
And if we invert that, we can work out who was omitted: select * from people where age > 30;
1 2 3 4 5 |
|
You can also combine WHERE
clauses to search inside of a range: select name, email, age from people where age >= 30 and age <= 40;
1 2 3 4 |
|
We've used AND
to create a second "part" to the WHERE
clause.
We can do other things with a WHERE
clause, too. Here's a table of some common operations:
Operator | Meaning | Example |
---|---|---|
= | Equal to | select * from people where age = 44; |
<> or != | Not equal to | select * from people where age <> 38; |
< | Less than | select * from people where age < 30; |
> | Greater than | select * from people where age > 30; |
<= | Less than or equal to | select * from people where age <= 20; |
>= | Greater than or equal to | select * from people where age >= 21; |
Using WHERE
and LIKE
#
With the WHERE
clause we can check for specific values or ranges, etc, but what if we want to search for names that are "like" a particular pattern? Let's look at an example.
I want to find people who have a name beginning with m
(or M
): select * from people where lower(name) like 'm%';
1 2 3 4 5 6 7 |
|
I've used three new concepts here: the lower()
function to change all upper case characters in the name
column to their lower case equivalents; the LIKE
operator in the clause; and the m%
pattern.
The lower()
function has an obvious effect on the value inside of the name
column. You should research this function, and other functions, so you're aware of what's available.
We've used LIKE
in place of the other operators we can use inside of a WHERE
clause, like =
, >
, or <=
, etc. Instead, we're using the LIKE
operator to say we want values like the pattern we provided.
And the pattern we provided was m%
. The %
symbol is a wild card that means all - it's like *
in other contexts. There is a whole bunch of things you can do with pattern matching. Here's a few options:
Pattern | Meaning | Example |
---|---|---|
% | Wildcard match | select * from people where name like 'm%'; |
_ | Specific letter or character wildcard | select * from people where name like '_ich%'; |
Using WHERE
with IN
#
Similar to the LIKE
operator, the IN
operator allows us to search for values in a range or list: select * from people where age in (19, 21, 44);
1 2 3 4 5 6 |
|
These are exact matches. You can also replace the list of numbers with a subquery, which is getting a bit advanced, but here's an example: select * from people where age in (select age from people where age <= 25);
1 2 3 4 5 6 7 |
|
I'm sure you can imagine just how powerful a subquery can be.
Ordering our results#
Let's take the above example, repeat it, and order the results by the age column: select * from people where age in (select age from people where age <= 25) order by age;
1 2 3 4 5 6 7 |
|
And we can change the order too by changing order by age
to order by age desc
:
1 2 3 4 5 6 7 |
|
That's reversed the order.
Adding a column#
We need another column: type
. I want to add this column because I'm pretty certain "Merlo Coffee" isn't a person, so I want to classify our data based on them being a person or a business.
Let's add the column: alter table people add column type text not null default 'person';
1 2 3 4 5 6 7 8 9 10 |
|
I've used the ALTER TABLE
command to literally alter the table and add a column. I used ADD COLUMN
to specify that I want to ADD
a new COLUMM
. You can do other things like deleting a column or changing an existing one. You can also update indexes and other more advanced attributes about columns.
I defined the new column as type TEXT NOT NULL
and I set the DEFAULT
value to person
. Above you can see I've done a SELECT
statement and I can now see the new column. Everyone is a person though, so let's update the "Merlo Coffee" column: update people set type = 'business' where id = 6;
1 2 3 4 5 6 7 8 9 10 |
|
You can do a lot with the ALTER TABLE
command, but this is sufficient for now.
Deleting our table#
Let's now wind down and DROP
our table, because our people table isn't needed anymore: drop table people;
1 2 3 |
|
Done.
Deleting our database#
With SQLite, deleting the database involves leaving the SQLite tool (Ctrl+D) and deleting the file. In MySQL, PostgreSQL, SQL Server, etc. you'd use the DROP DATABASE
command.
Summary#
You're not going to be doing much SQL in your day-to-day life as a systems administrator, but it's useful to know how-to manage a database directly using SQL. This can be useful in multiple situations.
Next#
Now we're going to look at a more complex, server/client model database called MySQL.