Buscar

Essential SQL_ A Gentle Introdu - Bala Paranj

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 109 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 109 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 109 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Table of Contents
 
1. About the Author 
2. Introduction 
3. Create, Insert and Select Statements 
4. Sorting 
5. Search Conditions 
6. Advanced Search Conditions 
7. Wildcard Search 
8. Calculated Fields 
9. Aggregate Functions 
10. Grouping Data 
11. Subqueries 
12. Joins 
13. Inner Join 
14. Advanced Joins 
15. Update and Delete 
16. Constraints 
17. Indexes 
About the Author
Bala Paranj has a Master's degree in Electrical Engineering from Wichita
State University. He began working in the IT industry in 1996. He started his
career as a Technical Support Engineer and then became a Web Developer
using Perl, Java and Ruby.
He is available for freelance work. Please contact him at support@zepho.com
or via Ruby Plus. He is also working on screencasts based on this book. If
you want notification about the release, please contact him.
https://www.rubyplus.com/contact
Introduction
What is a Database?
A database is a container that helps us to organize data. Databases are good at
storing large amounts of data in one place and make it easier to query the
data, add, update and delete data.
There are many types of databases, relational, object-oriented and document-
based. We will be focusing only on relational database. Most of the NoSQL
databases are documented based systems. They have their own query
language that have some similarity to SQL. So it is useful to learn SQL.
What is Relational?
According to the dictionary relational means things that relate to other things.
The relational model is a way to describe the data and the relationship
between those data. In a relational database, data is stored in a Table. A Table
is something that has a name. The table names describe the type of data that
is stored in that table. Every table also has a collection of columns that define
data that are stored in the Table.
Data is stored in columns. Every column has a name. Every column also has
a restriction that can restrict the size and the type of data that can be stored in
that column. So columns can store numbers, strings, date etc based on their
type. Columns can have restrictions on the value of data that could be stored
in them. Every column can be required or optional. The required columns
must have values whereas the optional columns do not force us to provide
any value. It could be a blank string or NULL value.
A column can be a Key. A Primary Key can uniquely identify that row.
Because the value in that column for that row is unique. No other row in that
table can have that same value. Now, if another table has a column that
contains that same key, we can then merge those two tables together. We can
query them together. A Foreign Key means that column's value is the same as
the Primary Key in another table. This allows rows the related tables to be
linked together. Keys establish the relationship between tables.
What is SQL?
SQL stands for Structured Query Language. SQL is what is a special-purpose
programming language. SQL is specifically built to manipulate relational
databases. It's a declarative language. So, we basically declare statements,
and the database system executes those statements. SQL is based on English,
so it is human readable. When we put SQL into a statement, we create an
actionable sentence. So a valid SQL statement is made up of a set of valid
actionable words. SQL is not case sensitive. Most SQL statements start with
a command. Generally that command is some sort of a verb to tell the
database to do something.
It has two parts. One is a part that is for defining the data in a relational
database, and the other part is a language for querying and manipulating that
data. By the end of this series of articles, you will be able to create a
database, query a database, add, update and delete data.
Summary
In this chapter you learned the meaning of the terminology used in relational
database. This gives you the background required to learn the SQL basics in
subsequent chapters.
Create, Insert and Select Statements
In this chapter, you will learn how to create a database, create tables, insert
data and retreive data from database.
Install Sqlite3
Install the sqlite3 gem.
$ gem install sqlite3
Output of running the command.
Fetching: sqlite3-1.3.9.gem (100%)
Building native extensions. This could take a while...
Successfully installed sqlite3-1.3.9
1 gem installed
Create a Database
When you type sqlite3 with a file name that ends in .sqlite3, sqlite3 gem will
automatically create an empty database.
$ sqlite3 play.sqlite3
SQLite version 3.7.7 2011-06-25 16:35:41
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
To view the tables:
sqlite> .tables
This will return no output, since we don't have any tables yet.
Create a Table
Use CREATE TABLE <table name> as follows:
sqlite> CREATE TABLE users(
 ...> id int primary key not null,
 ...> first_name char(50),
 ...> last_name char(50),
 ...> email char(50) not null);
sqlite> .tables
users
We see only one table called users.
Counting Records
To count the number of records in a table, use count(*) in the select statement
as follows:
sqlite> select count(*) from users;
0
Here we see no records, since we don't have any data in the users table yet.
Inserting Rows
Let's insert some rows in the user table.
sqlite> INSERT INTO users(first_name, last_name, email)
 ...> VALUES('bugs', 'bunny', 'bbunny@disney.com');
Error: users.id may not be NULL
We get an error because we have a 'not null' constraint on the primary key id
of the users table. So, we need to provide it:
sqlite> INSERT INTO users(id, first_name, last_name, email)
 ...> VALUES(1,'bugs', 'bunny', 'bbunny@disney.com');
Now if we count again, we get:
sqlite> select count(*) from users;
1
Retrieving All Columns
To retrieve data for all columns, use * after the select keyword as follows:
sqlite> select * from users;
1|bugs|bunny|bbunny@disney.com
Let's turn on the column names to be displayed.
sqlite> .headers on
sqlite> select * from users;
id|first_name|last_name|email
1|bugs|bunny|bbunny@disney.com
Let's insert a second row into the users table.
sqlite> INSERT INTO users(id, first_name, last_name, email)
 ...> VALUES(2,'daffy', 'duck', 'daffy@disney.com');
sqlite> select count(*) from users;
count(*)
2
Now we have two rows in the users table.
Retrieving Single Column
sqlite> select first_name from users where id=2;
first_name
daffy
Let's make the output pretty with the column name and it's data aligned.
sqlite> .mode column
sqlite> select first_name from users where id=2;
first_name
----------
daffy
If you retrieve all the columns, you will get a nice output:
sqlite> select * from users;
id first_name last_name email 
---------- ---------- ---------- -----------------
1 bugs bunny bbunny@disney.com
2 daffy duck daffy@disney.com
Retrieving Multiple Columns
To retrieve data for multiple columns from a table, specify the column names
after the select keyword separated by a comma, like this:
sqlite> select first_name, last_name from users;
first_name last_name 
---------- ----------
bugs bunny 
daffy duck
Exercise
Insert three records into users table. One of the record must have the same
first_name any one of the existing record.
Answer
sqlite> INSERT INTO users(id, first_name, last_name, email)
 ...> VALUES(3,'porky', 'pig', 'ppig@disney.com');
sqlite> INSERT INTO users(id, first_name, last_name, email)
 ...> VALUES(4,'pluto', 'dog', 'pdog@disney.com');
sqlite> INSERT INTO users(id, first_name, last_name, email)
 ...> VALUES(5,'pluto', 'pet', 'pdog@disney.com');
sqlite> select count(*) from users;
count(*) 
----------
5
Limiting Results
To limit the number of rows to retrieve from the database, use the 'limit'
keyword:
sqlite> select * from users limit 2;
id first_name last_name email---------- ---------- ---------- -----------------
1 bugs bunny bbunny@disney.com
2 daffy duck daffy@disney.com
To get the next two rows, specify where to start and the number of rows to
retrieve:
sqlite> select * from users limit 2 offset 2;
id first_name last_name email 
---------- ---------- ---------- ---------------
3 porky pig ppig@disney.com
4 pluto dog pdog@disney.com
In this example it starts from row 3 (offset = 2) and retrieves two records
(limit = 2).
Retrieving Distinct Rows
We have 5 records in the users table.
sqlite> select * from users;
id first_name last_name email 
---------- ---------- ---------- -----------------
1 bugs bunny bbunny@disney.com
2 daffy duck daffy@disney.com 
3 porky pig ppig@disney.com 
4 pluto dog pdog@disney.com 
5 pluto pet pdog@disney.com
If we want to retrieve only unique user names :
sqlite> select DISTINCT(first_name) from users;
first_name
----------
bugs 
daffy 
pluto 
porky
Summary
In this chapter, you learned how to create a new database, create a table,
populate the table with data and the basics of SQL SELECT statement. In the
next article, you will learn how to sort the retrieved data.
Sorting
In this chapter, you will learn how to use ORDER By clause to sort retrieved
data.
Sorting Single Column
When you select a column, the data seems to be not ordered:
sqlite> select first_name from users;
first_name
----------
bugs 
daffy 
porky 
pluto 
pluto 
tasmanian 
tweety 
elmer 
speedy 
yosemite
However, if you select the primary key and the first name:
sqlite> select id, first_name from users;
id first_name
---------- ----------
1 bugs 
2 daffy 
3 porky 
4 pluto 
5 pluto 
6 tasmanian 
7 tweety 
8 elmer 
9 speedy 
10 yosemite
You see that it is displayed in the order the record was inserted into the
database. You should not rely on this default behavior since the ordering can
be changed when you delete and update records in the users table. It is a good
practice to explicitly specify the sort order.
sqlite> select first_name from users order by first_name;
first_name
----------
bugs 
daffy 
elmer 
pluto 
pluto 
porky 
speedy 
tasmanian 
tweety 
yosemite
You can now see that these are ordered by the first_name and not by the
primary key:
sqlite> select id, first_name from users order by first_name;
id first_name
---------- ----------
1 bugs 
2 daffy 
8 elmer 
4 pluto 
5 pluto 
3 porky 
9 speedy 
6 tasmanian 
7 tweety 
10 yosemite
Sorting by Multiple Columns
Here the data is not sorted in any order:
sqlite> select last_name, first_name from users;
last_name first_name
---------- ----------
bunny bugs 
duck daffy 
pig porky 
dog pluto 
pet pluto 
devil tasmanian 
bird tweety 
fudd elmer 
gonzales speedy 
sam yosemite
Let's sort the users first by last_name and then first_name:
sqlite> select last_name, first_name from users order by last_name, first_name;
last_name first_name
---------- ----------
bird tweety 
bunny bugs 
devil tasmanian 
dog pluto 
duck daffy 
fudd elmer 
gonzales speedy 
pet pluto 
pig porky 
sam yosemite
Specifying Sort Direction
In the previous examples, the sorting by default was in ascending order, if
you want to order by descending, you can use DESC keyword:
sqlite> select first_name from users order by first_name desc;
first_name
----------
yosemite 
tweety 
tasmanian 
speedy 
porky 
pluto 
pluto 
elmer 
daffy 
bugs
Here is another example, this time with multiple columns:
select last_name, first_name from users order by last_name desc, first_name;
last_name first_name
---------- ----------
sam yosemite 
pig porky 
pet pluto 
gonzales speedy 
fudd elmer 
duck daffy 
dog pluto 
devil tasmanian 
bunny bugs 
bird tweety
Summary
In this chapter, you learned how to sort data using the ORDER By clause in
the SELECT statement. This clause must be the last in the SELECT
statement. It can be used to sort data in ascending or descending order on one
or more columns.
Search Conditions
In this chapter, you will learn how to use the WHERE clause in SELECT
statement to filter data.
Where Clause
To avoid retrieving large number of records we specify search criteria to
extract a subset of the table's data.
sqlite> select * from users where id > 5;
id first_name last_name email 
---------- ---------- ---------- -----------------
6 tasmanian devil tdevil@disney.com
7 tweety bird tweety@disney.com
8 elmer fudd efudd@disney.com 
9 speedy gonzales gonzales@disney.c
10 yosemite sam sam@disney.com
Here the where clause is used as the filter condition to retrieve records with
primary key greater than 5.
Where Clause Operator
The example above used greater than as the operator for the search criteria.
We can also use any of the following operators:
 
1. Equality
2. Non-Equality
3. Less than
4. Less than or equal to
5. Not less than
6. Greater than
7. Greater than or equal to
8. Not greater than
9. Between two values
10. Is a NULL value
Here is the equality operator as the filter condition:
sqlite> select * from users where id = 5;
id first_name last_name email 
---------- ---------- ---------- ---------------
5 pluto pet pdog@disney.com
Here is the non-equality operator as the filter condition:
sqlite> select * from users where first_name <> 'pluto';
id first_name last_name email 
---------- ---------- ---------- -----------------
1 bugs bunny bbunny@disney.com
2 daffy duck daffy@disney.com 
3 porky pig ppig@disney.com 
6 tasmanian devil tdevil@disney.com
7 tweety bird tweety@disney.com
8 elmer fudd efudd@disney.com 
9 speedy gonzales gonzales@disney.c
10 yosemite sam sam@disney.com
The result filters out two of the records which contains pluto as the
first_name.
Exercise
Change the above non-equality query to use != instead of <>. What do you
see as the result?
Between a Range
We need to specify the beginning and end of the range as follows:
sqlite> select * from users where id between 5 and 10;
id first_name last_name email 
---------- ---------- ---------- ---------------
5 pluto pet pdog@disney.com
6 tasmanian devil tdevil@disney.c
7 tweety bird tweety@disney.c
8 elmer fudd efudd@disney.co
9 speedy gonzales gonzales@disney
10 yosemite sam sam@disney.com
Here we retrieve all records between 5 and 10, where 5 is the beginning and
10 is the end of the range. The range values is separated by the AND
keyword.
NULL Value
When a column does not have any value, it contains a NULL value. Since our
databasedoes not contain any record with NULL value, let's first insert a
record with NULL value for last_name by not providing a value in the insert
statement.
sqlite> select * from users where last_name is NULL;
sqlite> INSERT INTO users(id, first_name, email)
 ...> VALUES(12,'bosko', 'bosko@disney.com');
sqlite> select * from users where last_name is NULL;
id first_name last_name email 
---------- ---------- ---------- --------------
12 bosko bosko@disney.com
In this case, bosko does not have any last_name, it is NULL in database
terminology.
Exercise
Experiment with the remaining where clause operators from the list shown in
the Where Clause Operator section by querying the users table.
Summary
In this chapter, you learned how to specify search criteria to filter data using
the WHERE clause of the SELECT statement. You also learned how to use
various WHERE clause operators.
Advanced Search Conditions
In this chapter, you will learn how to combine WHERE clauses to create
advanced data filters and how to use NOT and IN operators.
Multiple Conditions in WHERE
Clauses
You can use more than one search criteria by combining where clauses with
AND or OR clauses. The AND and OR is known as logical operators.
Create the table and populate some data as follows:
sqlite> CREATE TABLE products(
 ...> id int primary key not null,
 ...> price int,
 ...> name char(50),
 ...> user_id int not null)
 ...> ;
sqlite> .tables
products users 
sqlite> INSERT INTO products(id, price, name, user_id)
 ...> VALUES(1, 10, 'Rock', 1);
sqlite> INSERT INTO products(id, price, name, user_id)
 ...> VALUES(2, 20, 'Sand', 1);
sqlite> INSERT INTO products(id, price, name, user_id)
 ...> VALUES(3, 30, 'Carrot', 1);
sqlite> INSERT INTO products(id, price, name, user_id)
 ...> VALUES(4, 40, 'Hammer', 1);
The AND Operator
You can use AND operator to filter by more than one column as follows:
sqlite> select * from products where user_id = 1 AND price < 30;
id price name user_id 
---------- ---------- ---------- ----------
1 10 Rock 1 
2 20 Sand 1
We have two conditions that is joined by the AND logical operator. In this
case the user_id must be 1 and the price must be less than 30. We have 4
records as demonstrated below:
sqlite> select * from products;
id price name user_id 
---------- ---------- ---------- ----------
1 10 Rock 1 
2 20 Sand 1 
3 30 Carrot 1 
4 40 Hammer 1
We found only two records when we applied the multiple conditions to the
query. You can have as many conditions as you want separated by AND
keyword.
The OR Operator
The OR operator is used to retrieve rows that match any of the condition in
the WHERE clause. Insert two records for product that belongs to different
users.
sqlite> INSERT INTO products(id, price, name, user_id)
 ...> VALUES(5, 40, 'Tree', 2);
sqlite> INSERT INTO products(id, price, name, user_id)
 ...> VALUES(6, 80, 'Cage', 3);
Let's retrieve all products that belong to user with id 2 or 3:
sqlite> select id, name, price from products where user_id=2 OR user_id = 3;
id name price 
---------- ---------- ----------
5 Tree 40 
6 Cage 80
Combining AND and OR Operators
Use parenthesis to group multiple conditions to avoid problems due to the
order of evaluation of the logical operators. Here is an example to combine
logical operators:
select id, user_id, name, price from products where (user_id = 1 OR user_id = 2) AND price > 
id user_id name price 
---------- ---------- ---------- ----------
4 1 Hammer 40 
5 2 Tree 40
You can see that there are 5 products that does not have the condition to filter
products with price greater than 30.
sqlite> select id, user_id, name, price from products where user_id = 1 OR user_id = 
id user_id name price 
---------- ---------- ---------- ----------
1 1 Rock 10 
2 1 Sand 20 
3 1 Carrot 30 
4 1 Hammer 40 
5 2 Tree 40
The IN Operator
The IN operator is used to specify a range of conditions. The results contain
matches that satisfy any of the conditions.
sqlite> select user_id, name, price from products where user_id IN (1,2,5);
user_id name price 
---------- ---------- ----------
1 Rock 10 
1 Sand 20 
1 Carrot 30 
1 Hammer 40 
2 Tree 40
In this example there are four rows that match the first value in the comma
separated list, just one row for the second value and no rows for user_id = 5,
because there is products that belongs to user_id = 5.
select user_id from products;
user_id 
----------
1 
1 
1 
1 
2 
3
There are products only for user_id = 1, 2 and 3.
The NOT Operator
The NOT is a negation operator that is always used in conjunction with
another operator.
sqlite> select * from products where NOT user_id = 1;
id price name user_id 
---------- ---------- ---------- ----------
5 40 Tree 2 
6 80 Cage 3
Here we retrieve all rows that does not belong to user_id = 1.
We could have accomplished the same thing with the <> operator as follows:
sqlite> select * from products where user_id <> 1;
id price name user_id 
---------- ---------- ---------- ----------
5 40 Tree 2 
6 80 Cage 3
Summary
In this chapter you learned how to use multiple conditions with WHERE
clauses by combining AND and OR operators. You also learned how to use
the IN and NOT operators.
Wildcard Search
In this chapter you will learn how to use wildcard for searches using the
LIKE operator.
The LIKE Operator
The Percent Wildcard
Let's insert few more rows to the products table.
sqlite> INSERT INTO products(id, price, name, user_id)
 ...> VALUES(7, 80, 'Cage Wire', 3);
sqlite> INSERT INTO products(id, price, name, user_id)
 ...> VALUES(8, 80, 'Camel Rope', 3);
The wildcard search can only be used with string fields. Let's search for
product names that has 'Ca' in it.
sqlite> select id, name from products where name LIKE 'Ca%';
id name 
---------- ----------
3 Carrot 
6 Cage 
7 Cage Wire 
8 Camel Rope
If we do :
sqlite> select id, name from products where name LIKE 'age%';
We don't get any results, to find the product with Cage and Cage Wire, we
can modify the query as follows:
sqlite> select id, name from products where name LIKE '%age%';
id name 
---------- ----------
6 Cage 
7 Cage Wire
So, the percent sign in the beginning matches any number of occurrences of
any character before the letter 'a'. The percent sign at the end of 'age' matches
any number of occurrences of any character after the string 'age'.
We can use the wildcard character anywhere in the string:
sqlite> select id, name from products where name LIKE 'C%e';
id name 
---------- ----------
6 Cage 
7 Cage Wire 
8 Camel Rope
Here we search for products that begins with the letter 'C' and has any
number of characters after that and ends in the letter 'e'.
The Underscore Wildcard
The underscore wildcard is used to match just a single character. Here is an
example:sqlite> select id, name from products where name LIKE '_ock';
id name 
---------- ----------
1 Rock
Here we match product with the name that has any letter before the 'ock'. We
can also combine both the wildcards:
sqlite> select id, name from products where name LIKE '_am%';
id name 
---------- ----------
4 Hammer 
8 Camel Rope
Summary
In this chapter you learned how to use wildcards to search text fields in the
WHERE clause. You learned about the percent and the underscore wildcards.
Calculated Fields
In this chapter, you will learn about calculated fields. Calculated fields are
useful to calculate total, averages or other calculations based on table data.
The calculated field does not exist in the tables, it is created on demand
within a SELECT statement. Why do we need to let the database do the
calculation instead of doing it in your client code? Because it is faster to
perform the calculations on the database server.
Concatenating Fields
Let's display the name of all the users by concatenating the first_name and
last_name.
sqlite> select first_name || ' ' || last_name from users;
first_name || ' ' || last_name
------------------------------
bugs bunny 
daffy duck 
porky pig 
pluto dog 
pluto pet 
tasmanian devil 
tweety bird 
elmer fudd 
speedy gonzales 
yosemite sam 
sylvester
Here we are using the two pipes || operator to concatenate first_name and
last_name. You can change the name of the resulting header to name by
using the AS keyword. The new header 'name' is an alias for the concatenated
field.
sqlite> select first_name || ' ' || last_name as name from users;
name 
----------
bugs bunny
daffy duck
porky pig 
pluto dog 
pluto pet 
tasmanian 
tweety bir
elmer fudd
speedy gon
yosemite s
sylvester
The last name is getting cut-off. Let's fix that by specifying the width for the
columns.
sqlite> .width 20 20
sqlite> select first_name || ' ' || last_name as name from users;
name 
--------------------
bugs bunny 
daffy duck 
porky pig 
pluto dog 
pluto pet 
tasmanian devil 
tweety bird 
elmer fudd 
speedy gonzales 
yosemite sam 
sylvester
Performing Calculations
Let's create a line_items table.
sqlite> CREATE TABLE line_items(
 ...> id int primary key not null,
 ...> product_id int not null,
 ...> quantity int,
 ...> price real,
 ...> order_number int);
sqlite> .tables
line_items products users
Populate line_times with some sample data.
sqlite> INSERT INTO line_items(id, product_id, quantity, price, order_number)
 ...> VALUES(1, 1, 4, 10, 1);
sqlite> INSERT INTO line_items(id, product_id, quantity, price, order_number)
 ...> VALUES(2, 3, 10, 10, 1);
sqlite> INSERT INTO line_items(id, product_id, quantity, price, order_number)
 ...> VALUES(3, 2, 1, 40, 1);
sqlite> INSERT INTO line_items(id, product_id, quantity, price, order_number)
 ...> VALUES(4, 4, 15, 30, 1);
We now have four rows in line_items table.
sqlite> select * from line_items;
id product_id quantity price order_number
-------------------- -------------------- ---------- ---------- ------------
1 1 4 10.0 1 
3 2 1 40.0 1 
2 3 10 10.0 1 
4 4 15 30.0 1
Let's calculate line_item_price for each of the line_items :
sqlite> select product_id, quantity, price, quantity * price AS line_item_price from line_items;
product_id quantity price line_item_price
-------------------- -------------------- ---------- ---------------
1 4 10.0 40.0 
2 1 40.0 40.0 
3 10 10.0 100.0 
4 15 30.0 450.0
The last column shows the line_item_price for each row in the line_items
table. You can add, subtract, multiply and divide to perform any
mathematical calculations.
Summary
In this chapter you learned how to use calculated fields and why it is used.
You also learned about the aliases for the calculated fields.
Aggregate Functions
In this chapter, you will learn how to use aggregate functions in SQL to
summarize table data. SQL provides functions to summarize data without
retrieving data. This saves bandwidth and avoids unnecessary retrieval of
data. This is useful for analysis and reporting purposes. These functions can
compute number of rows in a table, calculating sum of a set of rows in a
table, finding highest, lowest and average values in a table column.
The AVG() Function
Here is the average function :
sqlite> select AVG(price) AS average_price from products;
average_price 
--------------------
47.5
This query calculates the average price of all the products. You can also
calculate average price for a subset of rows.
sqlite> select AVG(price) AS average_price from products where user_id = 1;
average_price 
--------------------
25.0
In this example we calculate the average price of all products for a user with
user_id = 1.
The COUNT function
Let's count the number of products in the products table.
sqlite> select count(*) from products;
count(*) 
--------------------
8
Currently, we have 8 products. We have 12 rows in the users table.
sqlite> select * from users;
id first_name last_name email 
-------------------- -------------------- ---------- -----------------
1 bugs bunny bbunny@disney.com
2 daffy duck daffy@disney.com 
3 porky pig ppig@disney.com 
4 pluto dog pdog@disney.com 
5 pluto pet pdog@disney.com 
6 tasmanian devil tdevil@disney.com
7 tweety bird tweety@disney.com
8 elmer fudd efudd@disney.com 
9 speedy gonzales gonzales@disney.c
10 yosemite sam sam@disney.com 
11 sylvester sam@disney.com 
12 bosko sam@disney.com
We get 12 when we count the users table.
sqlite> select count(*) from users;
count(*) 
--------------------
12
If we want to ignore NULL values and count only the number of rows that
have values in a specific column, we can use count(column_name).
sqlite> select count(last_name) from users;
count(last_name) 
--------------------
11
Although we see two blank values in the last_name column, we see 11
because only one of the column is NULL. We can find out which row it is by
firing this query:
sqlite> select * from users where last_name is NULL;
id first_name last_name email 
-------------------- -------------------- ---------- --------------
12 bosko sam@disney.com
The other record contains a blank string, we can find the row with blank
string using this query:
sqlite> select * from users where last_name ='';
id first_name last_name email 
---------------------------------------- ---------- --------------
11 sylvester sam@disney.com
We can provide a different name for the column name using AS keyword:
sqlite> select count(last_name) as last_name_count from users;
last_name_count 
--------------------
11
The MAX function
Let's find the price of the most expensive product.
sqlite> select MAX(price) from products;
MAX(price) 
--------------------
80
Exercise
Change the above query so that the name of the column is called 'Most
Expensive'.
The MIN Function
Let's find the price of the cheapest product.
sqlite> select MIN(price) from products;
MIN(price) 
--------------------
10
The SUM Function
sqlite> select SUM(quantity) as ordered_items from line_items where order_number = 
ordered_items 
--------------------
30
The SUM function returns the sum of all the quantity in the line_items table,
the WHERE clause restricts it to the order_number = 1.
sqlite> select * from line_items where order_number = 1;
id product_id quantity price order_number
-------------------- -------------------- ---------- ---------- ------------
1 1 4 10.0 1 
3 2 1 40.0 1 
2 3 10 10.0 1 
4 4 15 30.0 1
There is data for line_items for only one order. If you add all the columns
under the quantity, you get 30. We can also use SUM to total calculated
values. Here is an example to calculate the total amount for order with
order_number = 1.
sqlite> select SUM(price * quantity) AS Total from line_items where order_number = 
Total 
--------------------
630.0
This is the total amount that a customer would pay when they checkout the
cart on the online store.
sqlite> select * from line_items;
id product_id quantity price order_number
-------------------- -------------------- ---------- ---------- ------------
1 1 4 10.0 1 
3 2 1 40.0 1 
2 3 10 10.0 1 
4 4 15 30.0 1
You can double check the calculated answer by multiplying the quantity and
price and adding them up.
Combining Aggregate Functions
Here is an example that combines aggregate functions.
sqlite> select count(*) as count, 
 avg(price) as average_price, 
 max(price) as maximum_price, 
 min(price) as minimum_price from products;
count average_price maximum_price minimum_price
-------------------- -------------------- ------------- -------------
8 47.5 80 10
Summary
In this chapter, you learned about aggregate functions. They are faster than if
you were to calculate these values in your code. They can be combined
together to perform powerful calculations quickly.
Grouping Data
In this chapter you will learn how to group data using GROUP BY and
HAVING clause in the SELECT statement.
Why Group Data?
In the previous article you learned aggregate functions that performed
calculations on all the data in a table or on data that satisfied a specific
condition of the WHERE clause. We were able to count the number of
products. If we want to count the number of products for each user we need
to use grouping. Grouping allows us to divide data into logical sets and
perform aggregate calculations on each group.
Group By Clause
Let's count the number of products that belong to each user in the products
table.
sqlite> select user_id, count(*) as product_count from products group by user_id;
user_id product_count 
-------------------- --------------------
1 4 
2 1 
3 3
The result shows that the user with user_id = 1 has 4 products, user_id = 2
has 1 product and user_id = 3 has 3 products. You can verify this by
manually calculating the number of products from the following query.
sqlite> select * from products;
id price name user_id 
-------------------- -------------------- ---------- ----------
1 10 Rock 1 
2 20 Sand 1 
3 30 Carrot 1 
4 40 Hammer 1 
5 40 Tree 2 
6 80 Cage 3 
7 80 Cage Wire 3 
8 80 Camel Rope 3
You can see that the user with user_id has only one product whereas users
with user_id 1 and 3 have 4 and 3 products respectively.
Having Clause
You can filter groups to include and exclude by using Having clause.
sqlite> select user_id, count(*) as count from products group by user_id having count(*) > 
user_id count 
-------------------- --------------------
1 4 
3 3
The having clause filters on the group and finds only the rows that has more
than 2 products for the user. You can verify this by looking at the records.
sqlite> select * from products;
id price name user_id 
-------------------- -------------------- ---------- ----------
1 10 Rock 1 
2 20 Sand 1 
3 30 Carrot 1 
4 40 Hammer 1 
5 40 Tree 2 
6 80 Cage 3 
7 80 Cage Wire 3 
8 80 Camel Rope 3
You see there is only one user with user_id = 2 with the number of products
less than or equal to 2.
Summary
In this article you learned how to use the GROUP BY and HAVING clauses
to perform aggregate functions on groups of data.
Subqueries
In this chapter, you will learn how to use subqueries. Subqueries are queries
that are embedded into other queries.
Let's create the orders table.
sqlite> CREATE TABLE orders(
 ...> id int primary key not null,
 ...> confirmation char(50),
 ...> customer_id int not null,
 ...> created_at datetime default current_timestamp
 ...> );
Let's insert some records into the order table.
sqlite> INSERT INTO orders(id, confirmation, customer_id)
 ...> VALUES(1, 1, 1);
sqlite> INSERT INTO orders(id, confirmation, customer_id)
 ...> VALUES(2, 2, 1);
sqlite> INSERT INTO orders(id, confirmation, customer_id) 
...> VALUES(3, 3, 2);
Let's create customers table.
sqlite> CREATE TABLE customers(
 ...> id int primary key not null,
 ...> name char(50),
 ...> email char(50)
 ...> );
Let's insert some records into the customers table.
sqlite> INSERT INTO customers(id, name, email)
 ...> VALUES(1, 'Big Spender', 'bspender@example.com');
sqlite> INSERT INTO customers(id, name, email)
 ...> VALUES(2, 'Big Saver', 'bsaver@example.com');
Problem
List all customers who ordered item with product_id = 1:
Step 1
sqlite> select order_number from line_items where product_id = 1;
order_number
------------
1
Step 2
sqlite> select customer_idfrom orders where id = 1;
customer_id
-----------
1
We use the order_number retrieved from step 1 as the value for id because, id
is the primary key of orders and order_number in line_items is basically the
order_id. It should have been named order_id to be clear.
Step 3
sqlite> select customer_id from orders where id IN (select order_number from line_items 
customer_id
-----------
1
We can have subquery that finds the primary key of orders as above. Now we
can list the customer details as follows.
sqlite> select name, email from customers where id IN (select customer_id from orders 
name email 
----------- --------------------
Big Spender bspender@example.com
Subqueries as Calculated Fields
Let's find out the total number of orders placed by every customer in the
customers table. Orders table has the orders with the corresponding
customer_id. We have two steps:
 
1. Get the list of customers from customers table.
2. For each customer, count the number of orders placed from the orders
table.
sqlite> select count(*) as number_of_orders from orders where customer_id = 1;
number_of_orders
----------------
2 
sqlite> select count(*) as number_of_orders from orders where customer_id = 2;
number_of_orders
----------------
1
Here is the subquery that uses calculated fields.
sqlite> select name, (select count(*) from orders where orders.customer_id = customers.id) as number_of_orders from customers;
name number_of_orders
----------- ----------------
Big Spender 2 
Big Saver 1
To avoid ambiguity we have the order.customer_id = customers.id, this
relates the orders table and the customers table.
Summary
In this chapter, you learned how to use subqueries in WHERE clause IN
operators and for populating calculated columns.
Joins
In this chapter, you will learn the why and how to use joins.
Why Joins?
We currently have products and users table. Here is the list of records they
contain.
sqlite> select * from products;
id price name user_id 
---------- ---------- ---------- ----------
1 10 Rock 1 
2 20 Sand 1 
3 30 Carrot 1 
4 40 Hammer 1 
5 40 Tree 2 
6 80 Cage 3 
7 80 Cage Wire 3 
8 80 Camel Rope 3 
sqlite> select * from users;
id first_name last_name email 
---------- ---------- ---------- -----------------
1 bugs bunny bbunny@disney.com
2 daffy duck daffy@disney.com 
3 porky pig ppig@disney.com 
4 pluto dog pdog@disney.com 
5 pluto pet pdog@disney.com 
6 tasmanian devil tdevil@disney.com
7 tweety bird tweety@disney.com
8 elmer fudd efudd@disney.com 
9 speedy gonzales gonzales@disney.c
10 yosemite sam sam@disney.com 
11 sylvester sam@disney.com 
12 bosko sam@disney.com
We are storing the name and email in it's own table instead of storing it in
products table. Updating the users information becomes easy since it is in just
one place. This also saves storage space. The users and products table are
related to each other through common values. In this case the user_id ties a
row in the product to a user in the users table. The id in users and products
uniquely identifies a row in that table. This id field is called a primary key.
The join is used to retrieve data from multiple tables with a single SELECT
statement. A single set of output is returned by matching the correct rows in
the multiple tables on the fly.
How to Join
The FROM clause in the SELECT select includes all the tables to be joined
and they are related to each other.
sqlite> select first_name as user_name, name as product_name, price as product_price from users, products 
user_name product_name product_price
---------- ------------ -------------
bugs Rock 10 
bugs Sand 20 
bugs Carrot 30 
bugs Hammer 40 
daffy Tree 40 
porky Cage 80 
porky Cage Wire 80 
porky Camel Rope 80
The first_name is in the users table whereas the product name and product
price is in the products table. The FROM clause has tables separated by
comma. These are the tables to be joined. The WHERE clause specifies that
primary key in users table (users.id) must match the foreign key of the user in
products table (products.user_id). The output shows data from two different
tables retrieved using a single SELECT statement. Let's see what happens
when we don't have the WHERE clause.
sqlite> select first_name, name, price from users, products;
first_name name price 
---------- ---------- ----------
bugs Rock 10 
bugs Sand 20 
bugs Carrot 30 
bugs Hammer 40 
bugs Tree 40 
bugs Cage 80 
bugs Cage Wire 80 
bugs Camel Rope 80 
daffy Rock 10 
daffy Sand 20 
daffy Carrot 30 
daffy Hammer 40 
daffy Tree 40 
daffy Cage 80 
daffy Cage Wire 80 
daffy Camel Rope 80 
porky Rock 10 
porky Sand 20 
porky Carrot 30 
porky Hammer 40 
porky Tree 40 
porky Cage 80 
porky Cage Wire 80 
porky Camel Rope 80 
pluto Rock 10 
pluto Sand 20 
pluto Carrot 30 
pluto Hammer 40 
pluto Tree 40 
pluto Cage 80 
pluto Cage Wire 80 
pluto Camel Rope 80 
pluto Rock 10 
pluto Sand 20 
pluto Carrot 30 
pluto Hammer 40 
pluto Tree 40 
pluto Cage 80 
pluto Cage Wire 80 
pluto Camel Rope 80 
tasmanian Rock 10 
tasmanian Sand 20 
tasmanian Carrot 30 
tasmanian Hammer 40 
tasmanian Tree 40 
tasmanian Cage 80 
tasmanian Cage Wire 80 
tasmanian Camel Rope 80 
tweety Rock 10 
tweety Sand 20 
tweety Carrot 30 
tweety Hammer 40 
tweety Tree 40 
tweety Cage 80 
tweety Cage Wire 80 
tweety Camel Rope 80 
elmer Rock 10 
elmer Sand 20 
elmer Carrot 30 
elmer Hammer 40 
elmer Tree 40 
elmer Cage 80 
elmer Cage Wire 80 
elmer Camel Rope 80 
speedy Rock 10 
speedy Sand 20 
speedy Carrot 30 
speedy Hammer 40 
speedy Tree 40 
speedy Cage 80 
speedy Cage Wire 80 
speedy Camel Rope 80 
yosemite Rock 10 
yosemite Sand 20 
yosemite Carrot 30 
yosemite Hammer 40 
yosemite Tree 40 
yosemite Cage 80yosemite Cage Wire 80 
yosemite Camel Rope 80 
sylvester Rock 10 
sylvester Sand 20 
sylvester Carrot 30 
sylvester Hammer 40 
sylvester Tree 40 
sylvester Cage 80 
sylvester Cage Wire 80 
sylvester Camel Rope 80 
bosko Rock 10 
bosko Sand 20 
bosko Carrot 30 
bosko Hammer 40 
bosko Tree 40 
bosko Cage 80 
bosko Cage Wire 80 
bosko Camel Rope 80
The output now has every row in the users table paired with every row in the
products table. They are paired without considering any logical relationship
between them exists or not. The is called the Cartesian Product and the
number of rows returned will be equal to the number of rows in users table
multiplied by the number of rows in the products table.
Summary
In this chapter you learned the basics of joins and how to use them. You also
learned about Cartesian Product. In the next chapter we will explore inner
joins.
Inner Join
In this chapter, you will learn how to use inner joins. In the previous chapter
on Joins, the join we used is called as equijoin or inner join. It is called inner
join because it is the intersection of the two tables. If you had two circles to
represent two tables, the common overlapping area is the inner join of those
two tables. Here is an example:
sqlite> select first_name as user_name, name as product_name, price as product_price from users INNER JOIN products ON users.id = products.user_id;
user_name product_name product_price
---------- ------------ -------------
bugs Rock 10 
bugs Sand 20 
bugs Carrot 30 
bugs Hammer 40 
daffy Tree 40 
porky Cage 80 
porky Cage Wire 80 
porky Camel Rope 80
Instead of comma separating the tables as we saw in the previous article on
join, here we have INNER JOIN between the table names. The WHERE
clause is replaced by ON keyword. Here is the query we used in the previous
article, you can compare both the queries and see the difference.
sqlite> select first_name as user_name, name as product_name, price as product_price from users, products WHERE users.id = products.user_id;
user_name product_name product_price
---------- ------------ -------------
bugs Rock 10 
bugs Sand 20 
bugs Carrot 30 
bugs Hammer 40 
daffy Tree 40 
porky Cage 80 
porky Cage Wire 80 
porky Camel Rope 80
The query is different, but the output is the same in both cases.
Joining Multiple Tables
You can join as many tables as you want. You have to list all the tables and
define the relationship between them. Let's consider an example where we
need to display product name, user name, product price and quantity for an
order with order_number = 1. We know that product name and product price
are stored in the products table. The user name is stored in the users table and
the quantity is in the line_items table. Before we join these tables, let's take a
look at the data to help us form the query.
sqlite> select * from line_items;
id product_id quantity price order_number
---------- ---------- ---------- ---------- ------------
1 1 4 10.0 1 
3 2 1 40.0 1 
2 3 10 10.0 1 
4 4 15 30.0 1 
sqlite> select * from products;
id price name user_id 
---------- ---------- ---------- ----------
1 10 Rock 1 
2 20 Sand 1 
3 30 Carrot 1 
4 40 Hammer 1 
5 40 Tree 2 
6 80 Cage 3 
7 80 Cage Wire 3 
8 80 Camel Rope 3 
sqlite> select * from users;
id first_name last_name email 
---------- ---------- ---------- -----------------
1 bugs bunny bbunny@disney.com
2 daffy duck daffy@disney.com 
3 porky pig ppig@disney.com 
4 pluto dog pdog@disney.com 
5 pluto pet pdog@disney.com 
6 tasmanian devil tdevil@disney.com
7 tweety bird tweety@disney.com
8 elmer fudd efudd@disney.com 
9 speedy gonzales gonzales@disney.c
10 yosemite sam sam@disney.com 
11 sylvester sam@disney.com 
12 bosko sam@disney.com
Let's now join these three tables to get the data.
sqlite> select name, first_name, price, quantity from line_items, products, users 
 ...> where products.user_id = users.id
 ...> and line_items.product_id = products.id
 ...> and order_number = 1;
Error: ambiguous column name: price
We get this error because we have price column in line_times as well as the
products table. So we need to explicitly indicate which table the price column
we are interested in resides. We can do that by prefixing the price with the
name of the table as follows:
sqlite> select name, first_name, line_items.price, quantity from line_items, products, users
 ...> where products.user_id = users.id
 ...> and line_items.product_id = products.id
 ...> and order_number = 1;
name first_name price quantity 
---------- ---------- ---------- ----------
Rock bugs 10.0 4 
Sand bugs 40.0 1 
Carrot bugs 10.0 10 
Hammer bugs 30.0 15
We had to specify line_items.price to avoid ambiguity. The WHERE clauses
are separated by AND keyword to specify the relationships between the
tables. The foreign key in the products table user_id is the primary key in
users table id. This is the first condition of the WHERE clause. The condition
relates the foreign key product_id in the line_items table to the primary key
of products, id in the products table. The final order_number = 1 condition
filters the results only for that order.
You might be wondering why I picked line_items price column instead of
products' price column. The reason is that once the line_items is created the
price column will not change. The price column in the products table can be
changed by the user who owns it anytime. This avoids people who are
shopping our products getting confused by sudden changes in the price of the
product they are about to buy.
Exercise
The first column in the above output is the name of the product. Change the
name of the column from 'name' to 'product name'.
Using Joins Instead of Subqueries
In the previous chapter on subqueries we had this query:
sqlite> select name, email from customers where id IN (select customer_id from orders 
name email 
----------- --------------------
Big Spender bspender@example.com
Let's use joins instead of subqueries. To create this query, it helps to list all
the table to be joined so that you can see the relationship between them. This
will be used in the WHERE clauses.
sqlite> select * from customers;
id name email 
---------- ----------- --------------------
1 Big Spender bspender@example.com
2 Big Saver bsaver@example.com 
sqlite> select * fromorders;
id confirmation customer_id created_at 
---------- ------------ ----------- -------------------
1 1 1 2014-10-25 00:11:51
2 2 1 2014-10-25 00:14:29
3 3 2 2014-10-25 01:16:10
sqlite> select * from line_items;
id product_id quantity price order_number
---------- ---------- ---------- ---------- ------------
1 1 4 10.0 1 
3 2 1 40.0 1 
2 3 10 10.0 1 
4 4 15 30.0 1
Here is the query:
sqlite> select name, email 
 ...> from customers, orders, line_items
 ...> where customers.id = orders.customer_id
 ...> and line_items.order_number = orders.id
 ...> and product_id = 1;
name email 
----------- --------------------
Big Spender bspender@example.com
As you can see the result is the same as using the subquery. Which one
should you use? Prefer joins because it more efficient.
Summary
In this chapter you learned the basics of relationships between tables that is
required to use joins. You also learned the most frequently used joins, the
inner join. In the next chapter, we will explore other types of joins.
Advanced Joins
In this chapter, you will learn about outer joins and how to use them with
aggregate functions.
Data Population
Populate a few records into the customers table as follows:
sqlite> INSERT INTO customers(id, name, email)
 ...> VALUES(3, 'Big Saver', 'bsaver2@example.com');
sqlite> INSERT INTO customers(id, name, email)
 ...> VALUES(4, 'Big Browser', 'browser@example.com');
We now have four records in the customers table.
sqlite> select * from customers; 
id name email 
---------- ----------- --------------------
1 Big Spender bspender@example.com
2 Big Saver bsaver@example.com 
3 Big Saver bsaver2@example.com 
4 Big Browser browser@example.com
Self Join
Let's get a list of customers who work for the same company for which
'bsaver@example.com' works. The first query must find out the customer
name for 'bsaver@example.com', where he works. Then, find a list of
customers who work for the same company. Here is one way of solving this
problem using subquery:
sqlite> select id, name, email from customers 
where name = (select name from customers where email='bsaver@example.com');
id name email 
---------- ---------- ------------------
2 Big Saver bsaver@example.com
3 Big Saver bsaver2@example.com
Here is another way of solving the problem that uses join.
sqlite> select c1.id, c1.name, c1.email from customers as c1, customers as c2 
 ...> where c1.name = c2.name 
 ...> and c2.email = 'bsaver@example.com';
id name email 
---------- ---------- ------------------
2 Big Saver bsaver@example.com
3 Big Saver bsaver2@example.com
Instead of joining two different tables, in this case we are joining with the
same table. The c1 and c2 are aliases for the customers table. The WHERE
clause condition filters the customer name that match on both customers
table. The second condition of the WHERE clause finds records for the
company where 'bsaver@example.com' works.
Natural Joins
sqlite> select c.*, o.id, o.created_at, li.product_id, li.quantity, li.price
 ...> from customers as c, orders as o, line_items as li
 ...> where c.id = o.customer_id
 ...> and li.order_number = o.id
 ...> and product_id = 1;
id name email id created_at product_id quantity price 
---------- ----------- -------------------- ---------- ------------------- -
--------- ---------- ----------
1 Big Spender bspender@example.com 1 2014-10-
25 00:11:51 1 4 10.0
In this example, a wildcard is used for the customers table only. All other
columns are explicitly specified to avoid retrieving duplicate columns.
Outer Joins
Let's find out how many orders is placed by every customer. You can use
joins with aggregate functions like this:
sqlite> select customer_id, count(*) as number_of_order from orders group by customer_id;
customer_id number_of_order
----------- ---------------
1 2 
2 1
This is same as the following query:
sqlite> select customers.id, orders.id 
 ...> from customers INNER JOIN orders
 ...> ON customers.id = orders.customer_id;
customer_id order_id 
----------- ----------
1 1 
1 2 
2 3
We see only two customers who have placed orders. What if we want to
include customers who have not placed any orders yet?
sqlite> select customers.id as customer_id, orders.id as order_id
 ...> from customers LEFT OUTER JOIN orders
 ...> on customers.id = orders.customer_id;
customer_id order_id 
----------- ----------
1 1 
1 2 
2 3 
3 
4
The left outer join query returns customers who have not placed any order
yet. It includes the rows in the left of the LEFT OUTER JOIN, customers,
even if they don't have any corresponding value in the other table, in this
case, orders table. Let's combine the joins with aggregate functions to list the
number of orders placed by every customer.
sqlite> select customers.id as customer_id, count(orders.id) as number_of_orders
 ...> from customers LEFT OUTER JOIN orders 
 ...> on customers.id = orders.customer_id
 ...> group by customers.id;
customer_id number_of_orders
----------- ----------------
1 2 
2 1 
3 0 
4 0
If you find any of the query difficult to follow, list all the data in all tables
and refer them while you analyze the query. Here is the complete list of all
data. For subqueries, run one query at a time and then combine them
together.
sqlite> select * from orders;
id confirmation customer_id created_at 
---------- ------------ ----------- -------------------
1 1 1 2014-10-25 00:11:51
2 2 1 2014-10-25 00:14:29
3 3 2 2014-10-25 01:16:10
sqlite> select * from line_items;
id product_id quantity price order_number
---------- ---------- ---------- ---------- ------------
1 1 4 10.0 1 
3 2 1 40.0 1 
2 3 10 10.0 1 
4 4 15 30.0 1 
sqlite> select * from customers;
id name email 
---------- ----------- --------------------
1 Big Spender bspender@example.com
2 Big Saver bsaver@example.com 
3 Big Saver bsaver2@example.com 
4 Big Browser browser@example.com
Summary
In this chapter you learned about self join where we join with the same table,
outer join and natural joins. You also learned how to use them in combination
with aggregate functions.
Update and Delete
In this chapter, you will learn how to use UPDATE and DELETE statements
to update and delete rows in a table.
Update
To update data in a table the UPDATE statement is used. Let's take a look at
the existing data in the customers table.
sqlite> select * from customers;
id name email 
---------- ----------- --------------------
1 Big Spender bspender@example.com2 Big Saver bsaver@example.com 
3 Big Saver bsaver2@example.com 
4 Big Browser browser@example.com
Let's now update the email for the customer with id = 1.
sqlite> update customers
 ...> set email = 'bspender@spender.com'
 ...> where id = 1;
The update statement takes the name of table to be updated followed by the
SET keyword with the column name set to a new value. In this example we
are updating just one row because of the WHERE condition. Now the change
made can be verified by looking at the customers table.
sqlite> select * from customers;
id name email 
---------- ----------- --------------------
1 Big Spender bspender@spender.com
2 Big Saver bsaver@example.com 
3 Big Saver bsaver2@example.com 
4 Big Browser browser@example.com
Let's now look at updating more than one column.
sqlite> update customers
 ...> set name = 'Bugs Bunny',
 ...> email = 'bbunny@disney.com'
 ...> where id = 1;
The only difference here is that we specify multiple columns to be updated
separated by comma after the SET keyword.
sqlite> select * from customers;
id name email 
---------- ---------- -----------------
1 Bugs Bunny bbunny@disney.com
2 Big Saver bsaver@example.co
3 Big Saver bsaver2@example.c
4 Big Browse browser@example.c
We see that both both the name and email has been changed to the new
values. To display the entire value for email column, let's increase the width
of that column.
sqlite> .width 2 25 25
sqlite> select * from customers;
id name email 
-- ------------------------- -------------------------
1 Bugs Bunny bbunny@disney.com 
2 Big Saver bsaver@example.com 
3 Big Saver bsaver2@example.com 
4 Big Browser browser@example.com
Delete
The DELETE statement is used to remove data from a table. Here is the list
of customers before delete.
sqlite> select * from customers;
id name email 
-- ------------------------- -------------------------
1 Bugs Bunny bbunny@disney.com 
2 Big Saver bsaver@example.com 
3 Big Saver bsaver2@example.com 
4 Big Browser browser@example.com
Let's delete the last record in the customers table.
sqlite> delete from customers
 ...> where id = 4;
You can see that the customer 'Big Browser' is not in customers table.
sqlite> select * from customers;
id name email 
-- ------------------------- -------------------------
1 Bugs Bunny bbunny@disney.com 
2 Big Saver bsaver@example.com 
3 Big Saver bsaver2@example.com
If you don't provide the WHERE clause in the delete statement, all records
will be deleted.
sqlite> delete from customers;
sqlite> select count(*) from customers;
count
--
0
Summary
In this article you learned how to use the UPDATE and DELETE statements
for changing and deleting rows in a table.
Constraints
In this chapter, you will learn about constraints, primary keys, foreign keys
and referential integrity.
What are Constraints?
Relational databases store data into multiple tables. There are relationships
that exist between the tables. That's why it's called Relational database. Keys
reference from one table to another. This is called referential integrity. In
our example, when we store a record in the line_items table, the
order_number references the id column in the orders table. There cannot be a
line_items record that does not have a order_number or a order_number that
does not exist in the orders table. This would violate the referential integrity.
Relational databases enforce referential integrity by imposing constraints on
database tables. You can create the constraints when you use the CREATE
TABLE or ALTER TABLE commands.
Primary Keys
A primary key ensures that values in a column are unique. So, you can
uniquely identify each row in a table. This makes the UPDATE or DELETE
safe to use, ie., they don't affect other rows. Let's create a credit_cards table.
sqlite> CREATE TABLE credit_cards
 ...> (
 ...> id int primary key not null,
 ...> type char(10) not null,
 ...> user_id int not null
 ...> );
The keyword primary key in the table definition defines id as the primary
key of the credit_cards table. We can see the new table.
sqlite> .tables
credit_cards line_items products 
customers orders users
We can also see the table structure.
sqlite> .schema credit_cards
CREATE TABLE credit_cards
(
id int primary key not null,
type char(10) not null,
user_id int not null
);
Foreign Keys
A foreign key is a column in a table that references the primary key in
another table. They are used to enforce referential integrity.
Let's delete the table we just created.
sqlite> drop table credit_cards;
sqlite> .tables
customers line_items orders products users
Now lets create the credit_cards table again that will use a foreign key.
sqlite> CREATE TABLE credit_cards
 ...> (
 ...> id int primary key not null,
 ...> type char(10) not null,
 ...> user_id int not null,
 ...> FOREIGN KEY (user_id) REFERENCES users(id) 
 ...> );
We can see the schema of the new table.
sqlite> .schema credit_cards
CREATE TABLE credit_cards
(
id int primary key not null,
type char(10) not null,
user_id int not null,
FOREIGN KEY (user_id) REFERENCES users(id) 
);
Here the table definition uses the FOREIGN KEY keyword to make the
user_id field a foreign key, it uses REFERENCES to indicate that it
references the id field in users table. Now, we cannot create any records in
the credit_cards table that does not have a user_id value that does not exist in
the users table.
Here is an example that creates a new credit card for Yosemite Sam.
sqlite> INSERT INTO credit_cards(id, type, user_id)
 ...> VALUES (1, 'VISA', 10);
sqlite> select * from credit_cards;
id type user_id 
---------- ---------- ----------
1 VISA 10 
sqlite> select * from users;
id first_name last_name email 
---------- ---------- ---------- -----------------
1 bugs bunny bbunny@disney.com
2 daffy duck daffy@disney.com 
3 porky pig ppig@disney.com 
4 pluto dog pdog@disney.com 
5 pluto pet pdog@disney.com 
6 tasmanian devil tdevil@disney.com
7 tweety bird tweety@disney.com
8 elmer fudd efudd@disney.com 
9 speedy gonzales gonzales@disney.c
10 yosemite sam sam@disney.com 
11 sylvester sam@disney.com 
12 bosko sam@disney.com
Here is an example that shows creating a row that violates the foreign key
constraint results in an error.
sqlite> INSERT INTO credit_cards(id, type, user_id)
 ...> VALUES (1, 'VISA', 13);
Error: column id is not unique
We can verify that there is only one record in the credit_cards table.
sqlite> select * from credit_cards;
id type user_id 
---------- ---------- ----------
1 VISA 10
Summary
In this article you learned about constraints, primary key and foreign key.
You also learned about how they enforce referential integrity.
Indexes
In this chapter, you will learn how and when to use indexes on one or more
columns in a table.
What are Indexes?
Tables are sorted by primary key, so retrieving rows using primary key is
fast. If you want to retrieve records whereyou use a filter condition that
contains some other column other than the primary key, the database will
start at the first row and look for matches from all the rows in the table. This
is slow. Indexes improve searching and sorting speed. You can define an
index on one or more columns so that the database server keeps a sorted list
of the records for fast lookup.
But indexes come with a cost:
 
Indexes improve the lookup performance at the cost of degrading the
performance of insert, update and delete operations. When any of the
data manipulation operations are executed, the database server has to
update the index dynamically.
Indexed data can take up more storage space than non-indexed data.
Data that is not unique such as country names will not be suitable for
indexing.
If you frequently sort data in a specific order, it could be a good
candidate for indexing.
Create Index
CREATE INDEX statement is used to create indexes. Let's create an index
on the name column of the products table.
sqlite> create index product_name_index
 ...> on products (name);
Indexes must have unique name. In this example, product_name_index is the
index name, ON is used to specify the table name to be indexed followed by
the columns to include in the index inside parentheses. You can describe the
schema of the products table to check if the index has been defined.
sqlite> .schema products
CREATE TABLE products(
id int primary key not null,
price int,
name char(50),
user_id int not null);
CREATE INDEX product_name_index
on products (name);
You can see the index definition after the create table definition.
Summary
In this chapter you learned how and when to use indexes in a table.
Table of Contents
About the Author
Introduction
Create, Insert and Select Statements
Sorting
Search Conditions
Advanced Search Conditions
Wildcard Search
Calculated Fields
Aggregate Functions
Grouping Data
Subqueries
Joins
Inner Join
Advanced Joins
Update and Delete
Constraints
Indexes
	About the Author
	Introduction
	Create, Insert and Select Statements
	Sorting
	Search Conditions
	Advanced Search Conditions
	Wildcard Search
	Calculated Fields
	Aggregate Functions
	Grouping Data
	Subqueries
	Joins
	Inner Join
	Advanced Joins
	Update and Delete
	Constraints
	Indexes

Outros materiais