PostgreSQL For Beginners
PostgreSQL For Beginners
org
Introduction
We have written this small book for those who only start
getting acquainted with the world of PostgreSQL. From
this book, you will learn:
Good luck!
1
About PostgreSQL
PostgreSQL is the most feature-rich free open-source
DBMS. Developed in the academic environment, this DBMS
has brought together a wide developer community through
its long history. Nowadays, PostgreSQL offers all the func-
tionality required by most customers and is actively used
all over the world to create high-load business-critical
systems.
Some History
www.dbooks.org
accepted standard at the time), and data storage struc-
ture.
3
of active users and developers, which was named “Post-
greSQL Global Development Group.”
Development
The Core team of the project takes all the main decisions
about developing and releasing new PostgreSQL versions.
At the moment, the team consists of five people.
www.dbooks.org
are accepted. Within the release cycle, beta versions ap-
pear. Closer to the end of the release cycle a release
candidate is built, and soon a new major version of Post-
greSQL is released.
Support
5
for PostgreSQL, including Russia-based Postgres Profes-
sional (www.postgrespro.com).
Current State
Security
www.dbooks.org
For user management and database access control, the
following features are provided:
Transaction Support
7
transactions never block writing ones, and writing never
blocks reading. This is true even for the strictest serial-
izable isolation level. Using an innovative Serializable
Snapshot Isolation system, this level ensures that there
are no serialization anomalies and guarantees that con-
current transaction execution leads to the same result as
one of possible sequential executions.
www.dbooks.org
• Built-in flexible full-text search system with support
for all the European languages (including Russian),
extended with effective index access methods.
9
Query Planner
Indexing
10
www.dbooks.org
• RUM: an enhancement of the GIN method for full-
text search. Available as an extension, this index
type can speed up phrase search and return the re-
sults sorted by relevance.
Cross-Platform Support
11
Its portable open-source C code allows to build Post-
greSQL on a variety of platforms, even if there is no pack-
age supported by the community.
Extensibility
• Data types
• Loadable extensions
12
www.dbooks.org
The standard PostgreSQL 10 package alone includes about
fifty extensions that have proved to be useful and reli-
able.
Availability
Independence
13
Installation and Quick Start
What is required to get started with PostgreSQL? In this
chapter, we’ll explain how to install and manage Post-
greSQL service, and then show how to set up a simple
database and create tables in it. We will also cover the
basics of the SQL language, which is used for data queries.
It’s a good idea to start trying SQL commands while you
are reading this chapter.
All examples in this book will also work with vanilla Post-
greSQL, which can be installed from the community web-
site or your package repository.
14
www.dbooks.org
For other operating systems, you can view installation in-
structions online: postgrespro.com/products/download.
Windows
Installation
15
Choose components:
16
www.dbooks.org
Installation folder:
17
You can also specify the directory to store the databases.
This directory will hold all the information stored in DBMS,
so make sure you have enough disk space if you are plan-
ning to keep a lot of data.
18
www.dbooks.org
Server options:
You can leave the default settings in all the other fields.
19
If you are planning to install Postgres Pro for educational
purposes only, you can select the “Use the default set-
tings” option for DBMS to take up less RAM.
20
www.dbooks.org
To temporarily stop the database server service, run the
“Stop Server” program from the Start menu subfolder that
you have selected at installation time:
To start the service, you can run the “Start Server” pro-
gram from the same folder.
21
• postgresql.conf is the main configuration file that
contains server parameters.
Installation
22
www.dbooks.org
For Ubuntu OS (currently supported versions are 14.04
“Trusty,” 16.04 “Xenial,” 17.10 “Artful”, and 18.04 “Bionic”),
you should use a little bit different commands:
$ locale
$ export LC_CTYPE=fr_FR.UTF8
$ export LC_COLLATE=fr_FR.UTF8
You should also make sure that the operating system has
the required locale installed:
23
$ locale -a | grep fr_FR
fr_FR.utf8
24
www.dbooks.org
Managing the Service and the Main Files
25
On some older versions of the operating systems, you
may have to view the log file /var/lib/pgpro/std-10/
pgstartup.log.
• /var/lib/pgpro/std-10/data/postgresql.conf
is the main configuration file that contains server
parameters.
• /var/lib/pgpro/std-10/data/pg_hba.conf de-
fines access settings. For security reasons, the ac-
cess is only allowed from the local system on behalf
of the postgres OS user by default.
Now it’s time to connect to the database and try out SQL.
26
www.dbooks.org
Trying SQL
Connecting via psql
27
around the database objects and display the data stored
in tables in a convenient format.
28
www.dbooks.org
symbols instead of letters, make sure that a TrueType font
is selected in the properties of the terminal window (typi-
cally, “Lucida Console” or “Consolas”).
Database
postgres=# \c test
29
You are now connected to database "test" as user
"postgres".
test=#
The command that we’ve just entered does not look like
SQL, as it starts with a backslash. This is a convention for
special commands that can only be used in psql (so if
you are using pgAdmin or another GUI tool, skip all com-
mands starting with a backslash, or try to find an equiva-
lent).
test=# \?
Tables
30
www.dbooks.org
For each column, a data type is defined. All the values in
the corresponding row fields must conform to this type.
You can use multiple built-in data types provided by Post-
greSQL (postgrespro.com/doc/datatype.html), or add
your own custom types. Here we’ll cover just a few main
ones:
• integer
• text
31
• c_no defines the course number represented as a
text string.
You can find the exact syntax of the CREATE TABLE com-
mand in documentation, or view command-line help right
in psql:
32
www.dbooks.org
test=# INSERT INTO courses(c_no, title, hours)
VALUES ('CS301', 'Databases', 30),
('CS305', 'Networks', 60);
INSERT 0 2
33
student can take exams in multiple courses, and each
exam can be taken by multiple students.
34
www.dbooks.org
Data Retrieval
Simple Queries
The result can contain several rows with the same data.
Even if all rows in the original table are different, the
data can appear duplicated if not all the columns are dis-
played:
35
test=# SELECT start_year FROM students;
start_year
------------
2014
2014
2015
(3 rows)
36
www.dbooks.org
test=# SELECT * FROM courses WHERE hours > 45;
c_no | title | hours
-------+----------+-------
CS305 | Networks | 60
(1 row)
Remember:
37
Joins
38
www.dbooks.org
test=# SELECT courses.title, exams.s_id, exams.score
FROM courses, exams
WHERE courses.c_no = exams.c_no;
title | s_id | score
-------------+------+-------
Databases | 1451 | 5
Databases | 1556 | 5
Networks | 1451 | 5
Networks | 1432 | 4
(4 rows)
39
test=# SELECT students.name, exams.score
FROM students
LEFT JOIN exams
ON students.s_id = exams.s_id
AND exams.c_no = 'CS305';
name | score
--------+-------
Anna | 5
Victor | 4
Nina |
(3 rows)
Note that the rows from the left table that don’t have
a counterpart in the right table are added to the result
(that’s why the operation is called LEFT JOIN). The corre-
sponding values in the right table are undefined in this
case.
40
www.dbooks.org
Don’t be afraid of joins. It is a common operation for
database management systems, and PostgreSQL has a
whole range of effective mechanisms to perform it. Do
not join data at the application level, let the database
server do the job. The server can handle this task very
well.
Subqueries
41
If a subquery used in the list of SELECT expressions does
not contain any rows, NULL is returned (as in the last row
of the sample result above).
test=# SELECT *
FROM exams
WHERE (SELECT start_year
FROM students
WHERE students.s_id = exams.s_id) > 2014;
s_id | c_no | score
------+-------+-------
1556 | CS301 | 5
(1 row)
Let’s display all students who have any scores in the spec-
ified course:
42
www.dbooks.org
There is also the NOT IN form of this predicate that re-
turns the opposite result. For example, the following
query returns the list of students who got only excellent
scores (that is, who didn’t get any lower scores):
43
In the examples above, we appended table names to col-
umn names to avoid ambiguity. However, it may be insuf-
ficient. For example, the same table can be used in the
query twice, or we can use a nameless subquery instead
of the table in the FROM clause. In such cases, you can
specify an arbitrary name after the query, which is called
an alias. You can use aliases for regular tables as well.
Let’s display student names and their scores for the “Data-
bases” course:
44
www.dbooks.org
Sorting
45
Grouping Operations
46
www.dbooks.org
such conditions in the HAVING clause. While the WHERE
conditions are applied before grouping (and can use the
columns of the original tables), the HAVING conditions
take effect after grouping (so they can also use the columns
of the resulting table).
47
UPDATE 1
Transactions
48
www.dbooks.org
Here we have applied the NOT NULL constraint, which for-
bids using undefined values.
test=# \d students
Table "public.students"
Column | Type | Modifiers
------------+---------+----------
s_id | integer | not null
name | text |
start_year | integer |
g_no | text |
...
You can also get the list of all tables available in the
database:
test=# \d
List of relations
Schema | Name | Type | Owner
--------+----------+-------+----------
public | courses | table | postgres
public | exams | table | postgres
public | groups | table | postgres
public | students | table | postgres
(4 rows)
49
Now let’s create a group “A-101” and move all students
into this group, making Anna its monitor.
test=# BEGIN;
BEGIN
50
www.dbooks.org
Not to get confused, we will indent the commands of
the second session for clarity. Will this session see our
changes?
postgres=# \c test
You are now connected to database "test" as user
"postgres".
test=# SELECT * FROM groups;
g_no | monitor
------+---------
(0 rows)
51
test=# COMMIT;
COMMIT
52
www.dbooks.org
Third, as the example has shown, other users will never
see inconsistent data not yet committed by the trans-
action. This property is called isolation. Thanks to this
property, DBMS can serve multiple sessions in parallel,
without sacrificing data consistency. PostgreSQL is known
for a very effective isolation implementation: several ses-
sions can run read and write queries in parallel, without
locking each other. Locking occurs only two different pro-
cesses try to change the same row simultaneously.
53
Useful psql Commands
\l List of databases.
54
www.dbooks.org
Conclusion
test=# \q
55
Demo Database
Description
General Information
56
www.dbooks.org
Bookings Airports
# book_ref # airport_code
* book_date * airport_name
* total_amount * city
* coordinates
* timezone
57
So, the main enitity is a booking.
58
www.dbooks.org
that each aircraft model has only one cabin configura-
tion. Database schema does not check that seat numbers
in boarding passes have the corresponding seats in the
aircraft cabin.
Bookings
Tickets
59
Note that neither the passenger ID, nor the name is per-
manent (for example, one can change the last name or
passport), so it is impossible to uniquely identify all tick-
ets of a particular passenger. For simplicity, let’s assume
that all passengers are unique.
Flight Segments
Each flight segment has its price (amount) and travel class
(fare_conditions).
Flights
60
www.dbooks.org
61
There is no such entity as a “connecting flight”: if there
are no direct flights from one airport to another, the ticket
simply includes several required flight segments.
• Scheduled
The flight is available for booking. It happens one
month before the planned departure date; before
that time, there is no entry for this flight in the
database.
• On Time
The flight is open for check-in (twenty-four hours
before the scheduled departure) and is not delayed.
• Delayed
The flight is open for check-in (twenty-four hours
before the scheduled departure), but is delayed.
• Departed
The aircraft has already departed and is airborne.
• Arrived
The aircraft has reached the point of destination.
• Cancelled
The flight is cancelled.
62
www.dbooks.org
Airports
Boarding Passes
Aircraft
63
Seats
Flights View
• flight duration
scheduled_duration, actual_duration.
64
www.dbooks.org
Routes View
65
Installation
• edu.postgrespro.com/demo-small-en.zip
A small database with flight data for one month
(21 MB, DB size is 280 MB).
• edu.postgrespro.com/demo-medium-en.zip
A medium database with flight data for three months
(62 MB, DB size is 702 MB).
• edu.postgrespro.com/demo-big-en.zip
A large database with flight data for one year
(232 MB, DB size is 2638 MB).
66
www.dbooks.org
$ sudo su - postgres
$ wget https://edu.postgrespro.com/demo-small-en.zip
$ zcat demo-small-en.zip | psql
postgres# \i demo-small-en-20170815.sql
Sample Queries
postgres=# \c demo
You are now connected to database "demo" as user
"postgres".
demo=#
67
All the entities we are interested in are stored in the
bookings schema. As you connect to the database, this
schema will be used automatically, so there is no need to
specify it explicitly:
68
www.dbooks.org
airport_code | city
--------------+--------------------------
YKS | Yakutsk
MJZ | Mirnyj
KHV | Khabarovsk
PKC | Petropavlovsk
UUS | Yuzhno-Sakhalinsk
(5 rows)
demo=# \c
You are now connected to database "demo" as user
"postgres".
69
If you change the language setting to Russian, the city
names will get translated into Russian:
Simple Queries
70
www.dbooks.org
Solution. “The day before yesterday” is counted from the
booking.now value, not from the current date.
SELECT t.passenger_name,
b.book_date
FROM bookings b
JOIN tickets t
ON t.book_ref = b.book_ref
JOIN boarding_passes bp
ON bp.ticket_no = t.ticket_no
JOIN flights f
ON f.flight_id = bp.flight_id
WHERE f.departure_airport = 'SVO'
AND f.arrival_airport = 'OVB'
AND f.scheduled_departure::date =
bookings.now()::date - INTERVAL '2 day'
AND bp.seat_no = '1A';
SELECT count(*)
FROM flights f
JOIN seats s
ON s.aircraft_code = f.aircraft_code
WHERE f.flight_no = 'PG0404'
AND f.scheduled_departure::date =
bookings.now()::date - INTERVAL '1 day'
AND NOT EXISTS (
SELECT NULL
FROM boarding_passes bp
WHERE bp.flight_id = f.flight_id
AND bp.seat_no = s.seat_no
);
71
The second approach uses the operation of set subtrac-
tion:
SELECT count(*)
FROM (
SELECT s.seat_no
FROM seats s
WHERE s.aircraft_code = (
SELECT aircraft_code
FROM flights
WHERE flight_no = 'PG0404'
AND scheduled_departure::date =
bookings.now()::date - INTERVAL '1 day'
)
EXCEPT
SELECT bp.seat_no
FROM boarding_passes bp
WHERE bp.flight_id = (
SELECT flight_id
FROM flights
WHERE flight_no = 'PG0404'
AND scheduled_departure::date =
bookings.now()::date - INTERVAL '1 day'
)
) t;
72
www.dbooks.org
Problem. Which flights had the longest delays? Print the
list of ten “leaders.”
SELECT f.flight_no,
f.scheduled_departure,
f.actual_departure,
f.actual_departure - f.scheduled_departure
AS delay
FROM flights f
WHERE f.actual_departure IS NOT NULL
ORDER BY f.actual_departure - f.scheduled_departure
DESC
LIMIT 10;
Aggregate Functions
73
SELECT f.flight_no,
f.scheduled_duration,
min(f.actual_duration),
max(f.actual_duration),
sum(CASE
WHEN f.actual_departure >
f.scheduled_departure +
INTERVAL '1 hour'
THEN 1 ELSE 0
END) delays
FROM flights_v f
WHERE f.departure_city = 'Moscow'
AND f.arrival_city = 'St. Petersburg'
AND f.status = 'Arrived'
GROUP BY f.flight_no,
f.scheduled_duration;
SELECT t.passenger_name,
t.ticket_no
FROM tickets t
JOIN boarding_passes bp
ON bp.ticket_no = t.ticket_no
GROUP BY t.passenger_name,
t.ticket_no
HAVING max(bp.boarding_no) = 1
AND count(*) > 1;
74
www.dbooks.org
Problem. How many people can be included into a single
booking according to the available data?
SELECT tt.cnt,
count(*)
FROM (
SELECT t.book_ref,
count(*) cnt
FROM tickets t
GROUP BY t.book_ref
) tt
GROUP BY tt.cnt
ORDER BY tt.cnt;
Window Functions
75
SELECT tf.ticket_no,
f.departure_airport,
f.arrival_airport,
f.scheduled_arrival,
lead(f.scheduled_departure) OVER w
AS next_departure,
lead(f.scheduled_departure) OVER w -
f.scheduled_arrival AS gap
FROM bookings b
JOIN tickets t
ON t.book_ref = b.book_ref
JOIN ticket_flights tf
ON tf.ticket_no = t.ticket_no
JOIN flights f
ON tf.flight_id = f.flight_id
WHERE b.book_date =
bookings.now()::date - INTERVAL '7 day'
WINDOW w AS (PARTITION BY tf.ticket_no
ORDER BY f.scheduled_departure);
SELECT passenger_name,
round( 100.0 * cnt / sum(cnt) OVER (), 2)
AS percent
FROM (
SELECT passenger_name,
count(*) cnt
FROM tickets
GROUP BY passenger_name
) t
ORDER BY percent DESC;
76
www.dbooks.org
Problem. Solve the previous problem for first names and
last names separately.
WITH p AS (
SELECT left(passenger_name,
position(' ' IN passenger_name))
AS passenger_name
FROM tickets
)
SELECT passenger_name,
round( 100.0 * cnt / sum(cnt) OVER (), 2)
AS percent
FROM (
SELECT passenger_name,
count(*) cnt
FROM p
GROUP BY passenger_name
) t
ORDER BY percent DESC;
Arrays
77
Solution. One of the easiest solutions is to work with an
array of airports converted from the list of airports in the
itinerary using the array_agg aggregate function. We
select the middle element of the array as the airport of
destination, assuming that the outbound and inbound
ways have the same number of stops.
WITH t AS (
SELECT ticket_no,
a,
a[1] departure,
a[cardinality(a)] last_arrival,
a[cardinality(a)/2+1] middle
FROM (
SELECT t.ticket_no,
array_agg( f.departure_airport
ORDER BY f.scheduled_departure) ||
(array_agg( f.arrival_airport
ORDER BY f.scheduled_departure DESC)
)[1] AS a
FROM tickets t
JOIN ticket_flights tf
ON tf.ticket_no = t.ticket_no
JOIN flights f
ON f.flight_id = tf.flight_id
GROUP BY t.ticket_no
) t
)
SELECT t.ticket_no,
t.a,
t.departure,
CASE
WHEN t.departure = t.last_arrival
THEN t.middle
ELSE t.last_arrival
END arrival,
(t.departure = t.last_arrival) return_ticket
FROM t;
78
www.dbooks.org
In this example, the tickets table is scanned only once.
The array of airports is displayed for clarity only; for large
volumes of data, it makes sense to remove it from the
query.
SELECT r1.departure_airport,
r1.arrival_airport,
r1.days_of_week dow,
r2.days_of_week dow_back
FROM routes r1
JOIN routes r2
ON r1.arrival_airport = r2.departure_airport
AND r1.departure_airport = r2.arrival_airport
WHERE NOT (r1.days_of_week && r2.days_of_week);
Recursive Queries
79
Solution. Here you have to find the shortest path in the
graph. It can be done with the following recursive query:
WITH RECURSIVE p(
last_arrival,
destination,
hops,
flights,
flight_time,
found
) AS (
SELECT a_from.airport_code,
a_to.airport_code,
array[a_from.airport_code],
array[]::char(6)[],
interval '0',
a_from.airport_code = a_to.airport_code
FROM airports a_from,
airports a_to
WHERE a_from.airport_code = 'UKX'
AND a_to.airport_code = 'CNN'
UNION ALL
SELECT r.arrival_airport,
p.destination,
(p.hops || r.arrival_airport)::char(3)[],
(p.flights || r.flight_no)::char(6)[],
p.flight_time + r.duration,
bool_or(r.arrival_airport = p.destination)
OVER ()
FROM p
JOIN routes r
ON r.departure_airport = p.last_arrival
WHERE NOT r.arrival_airport = ANY(p.hops)
AND NOT p.found
)
SELECT hops,
flights,
flight_time
FROM p
WHERE p.last_arrival = p.destination;
80
www.dbooks.org
Infinite looping is prevented by checking the hops array.
This query also uses the found attribute, but here it should
be calculated separately for each pair of airports.
81
WITH RECURSIVE p(
departure,
last_arrival,
destination,
hops,
found
) AS (
SELECT a_from.airport_code,
a_from.airport_code,
a_to.airport_code,
array[a_from.airport_code],
a_from.airport_code = a_to.airport_code
FROM airports a_from,
airports a_to
UNION ALL
SELECT p.departure,
r.arrival_airport,
p.destination,
(p.hops || r.arrival_airport)::char(3)[],
bool_or(r.arrival_airport = p.destination)
OVER (PARTITION BY p.departure,
p.destination)
FROM p
JOIN routes r
ON r.departure_airport = p.last_arrival
WHERE NOT r.arrival_airport = ANY(p.hops)
AND NOT p.found
)
SELECT max(cardinality(hops)-1)
FROM p
WHERE p.last_arrival = p.destination;
82
www.dbooks.org
Solution.
WITH RECURSIVE p(
last_arrival,
destination,
hops,
flights,
flight_time,
min_time
) AS (
SELECT a_from.airport_code,
a_to.airport_code,
array[a_from.airport_code],
array[]::char(6)[],
interval '0',
NULL::interval
FROM airports a_from,
airports a_to
WHERE a_from.airport_code = 'UKX'
AND a_to.airport_code = 'CNN'
UNION ALL
SELECT r.arrival_airport,
p.destination,
(p.hops || r.arrival_airport)::char(3)[],
(p.flights || r.flight_no)::char(6)[],
p.flight_time + r.duration,
least(
p.min_time, min(p.flight_time+r.duration)
FILTER (
WHERE r.arrival_airport = p.destination
) OVER ()
)
FROM p
JOIN routes r
ON r.departure_airport = p.last_arrival
WHERE NOT r.arrival_airport = ANY(p.hops)
AND p.flight_time + r.duration <
coalesce(p.min_time, INTERVAL '1 year')
)
83
SELECT hops,
flights,
flight_time
FROM (
SELECT hops,
flights,
flight_time,
min(min_time) OVER () min_time
FROM p
WHERE p.last_arrival = p.destination
) t
WHERE flight_time = min_time;
84
www.dbooks.org
Additional Features
Full-Text Search
85
using metadata to limit the search range, setting up se-
cure access to documents, and many more.
86
www.dbooks.org
test=# CREATE TABLE course_chapters(
c_no text REFERENCES courses(c_no),
ch_no text,
ch_title text,
txt text,
CONSTRAINT pkt_ch PRIMARY KEY(ch_no, c_no)
);
CREATE TABLE
Now we enter the text of the first lectures for our courses
CS301 and CS305:
87
-[ RECORD 2 ]-----------------------------------------
no | II
ch_title | First Steps
txt | Getting more fascinated with the world of
databases
-[ RECORD 3 ]-----------------------------------------
no | I
ch_title | Local Networks
txt | Here we start our adventurous journey
through the intriguing world of networks
will return the row from chapter II (but not from chap-
ter I, where the adjective “fascinating” is used):
-[ RECORD 1 ]-----------------------------------------
txt | Getting more fascinated with the world of
databases
88
www.dbooks.org
PostgreSQL provides the ILIKE operator, which allows not
to worry about letter cases; otherwise, you would also
have to take uppercase and lowercase letters into ac-
count. Naturally, an SQL expert can always use regular
expressions (search patterns). Composing regular expres-
sions is an engaging task, little short of art. But when
there is no time for art, it’s worth having a tool that can
simply do the job.
89
3. There are no prepositions, and neither there would
be any conjunctions or other parts of the sentence
that are unimportant for search (the so-called stop-
words).
90
www.dbooks.org
it converts a string to the tsquery data type used in
queries.
91
The assigned weights allow to display the search results
by their rank:
The {0.1, 0.0, 1.0, 0.0} array sets the weight. It is an op-
tional argument of the ts_rank_cd function. By default,
array {0.1, 0.2, 0.4, 1.0} corresponds to D, C, B, A. The word’s
weight increases the importance of the returned row,
which helps to rank the results.
92
www.dbooks.org
-[ RECORD 1 ]-----------------------------------------
ts_headline | with the fascinating database
<b>world</b>.
-[ RECORD 2 ]-----------------------------------------
ts_headline | with the <b>world</b> of databases.
-[ RECORD 3 ]-----------------------------------------
ts_headline | through the intriguing <b>world</b> of
networks
93
Once the initial shock had passed, it became clear that
for most real tasks such a simple structure was not enough.
Composite keys were introduced, and then groups of keys
appeared. Relational DBMS didn’t want to fall behind and
started adding new features typical of NoSQL.
94
www.dbooks.org
We can solve this problem using the json type or the
jsonb type, which appeared later. The jsonb type stores
data in a compact binary form and, unlike json, supports
indexes, which can speed up search by times.
95
Let’s check that all the data is available. For convenience,
let’s join the tables student_details and students with
the help of the WHERE clause, since the new table does
not contain students’ names:
96
www.dbooks.org
Suppose we are interested in entries that hold informa-
tion about students’ merits. We can access the values of
the “merits” key using a special operator ->>:
97
Make sure that this query only returns Nina, whose merits
are real.
This method does not always work. Let’s try to find out
which guitars our musician Victor is playing:
name | Victor
details | { "hobbies": +
| { "guitarist": +
| { "band": "Postgressors", +
| "guitars":["Strat","Telec"] +
| } +
| } +
| }
98
www.dbooks.org
de_id | name | ?column?
-------+--------+-------------------
2 | Victor | ["Strat","Telec"]
99
We can notice that apart from a different notation, the
order of values in the pairs has changed: Alex is now dis-
played before Mark. It’s not a disadvantage of jsonb as
compared to json, it’s simply its data storage specifics.
100
www.dbooks.org
test=# SELECT s.name,
jsonb_each(sd.details_b)
FROM student_details sd, students s
WHERE s.s_id = sd.s_id
AND sd.details_b @>
'{"merits":{"mother-of-five":{}}}' \gx
-[ RECORD 1 ]-------------------------------------
name | Nina
jsonb_each | (hobbies,"""cosplay""")
-[ RECORD 2 ]-------------------------------------
name | Nina
jsonb_each | (merits,"{""mother-of-five"":
{""Alex"": ""unknown"", ""Mark"":
""m"", ""Basil"": ""m"", ""Lucie"":
""f"", ""Simon"": ""m""}}")
To learn more about json and jsonb types and the func-
tions that can be used with them, see PostgreSQL docu-
mentation at postgrespro.com/doc/datatype-json and
postgrespro.com/doc/functions-json.
101
PostgreSQL
for Applications
A Separate User
102
www.dbooks.org
postgres=# \c appdb app localhost 5432
Password for user app: ***
You are now connected to database "appdb" as user
"app" on host "127.0.0.1" at port "5432".
appdb=>
The app user can work with their database without any
limitations. For example, this user can create a table:
Remote Connections
103
To connect to the database from the outside, you must
edit two files.
#listen_addresses = 'localhost'
listen_addresses = '*'
104
www.dbooks.org
The peer method means that PostgreSQL requests the
current username from the operating system and assumes
that the OS has already performed the required authenti-
cation check (prompted for the password). This is why on
Linux-like operating systems users usually don’t have to
enter the password when connecting to the server on the
local computer: it is enough to enter the password when
logging into the system.
So, for our purposes, add the following line to the end of
the pg_hba.conf file:
This setting allows the app user to access the appdb data-
base from any address if the correct password is entered.
105
Pinging the Server
PHP
106
www.dbooks.org
You can install PHP for Windows from the PHP website:
windows.php.net/download. The extension for Post-
greSQL is already included into the binary distribution,
but you must find and uncomment (by removing the semi-
colon) the following line in the php.ini file:
;extension=php_pgsql.dll
<?php
$conn = pg_connect('host=localhost port=5432 ' .
'dbname=appdb user=app ' .
'password=p@ssw0rd') or die;
$query = pg_query('SELECT * FROM greeting') or die;
while ($row = pg_fetch_array($query)) {
echo $row[0].PHP_EOL;
}
pg_free_result($query);
pg_close($conn);
?>
$ php test.php
Hello, world!
107
Perl
There are several Perl builds for Windows, which are listed
at www.perl.org/get.html. ActiveState Perl and Straw-
berry Perl already include the driver required for Post-
greSQL.
use DBI;
my $conn = DBI->connect(
'dbi:Pg:dbname=appdb;host=localhost;port=5432',
'app','p@ssw0rd') or die;
my $query = $conn->prepare('SELECT * FROM greeting');
$query->execute() or die;
while (my @row = $query->fetchrow_array()) {
print @row[0]."\n";
}
$query->finish();
$conn->disconnect();
$ perl test.pl
Hello, world!
108
www.dbooks.org
Python
import psycopg2
conn = psycopg2.connect(
host='localhost', port='5432', database='appdb',
user='app', password='p@ssw0rd')
cur = conn.cursor()
cur.execute('SELECT * FROM greeting')
rows = cur.fetchall()
for row in rows:
print row[0]
conn.close()
$ python test.py
Hello, world!
109
Java
import java.sql.*;
public class Test {
public static void main(String[] args)
throws SQLException {
Connection conn = DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/appdb",
"app", "p@ssw0rd");
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(
"SELECT * FROM greeting");
while (rs.next()) {
System.out.println(rs.getString(1));
}
rs.close();
st.close();
conn.close();
}
}
110
www.dbooks.org
We compile and execute the program specifying the path
to the JDBC class driver (on Windows, paths are separated
by semicolons, not colons):
$ javac Test.java
$ java -cp .:/usr/share/java/postgresql-jdbc4.jar \
Test
Hello, world!
Backup
$ createdb appdb2
$ psql -d appdb2 -f appdb.dump
111
pg_dump offers many features worth checking out: postgrespro.
com/doc/app-pgdump. Some of them are available only if
the data is dumped in an internal custom format. In this
case, you have to use the pg_restore utility instead of
psql to restore the data.
112
www.dbooks.org
What’s next?
113
However, this solution also has some obvious disadvan-
tages:
114
www.dbooks.org
joins, sorting, aggregation) are guaranteed to per-
form better than the application code since they
have been improved and optimized for years.
115
pgAdmin
pgAdmin is a popular GUI tool for administering Post-
greSQL. This application facilitates the main administra-
tion tasks, shows database objects, and allows to run SQL
queries.
Installation
116
www.dbooks.org
procedure is simple and straightforward, there is no need
to change the default options.
$ cd ~
$ virtualenv pgadmin4
$ cd pgadmin4
$ source bin/activate
Now let’s install pgAdmin itself. You can find the latest
available version here: www.pgadmin.org/download/
pgadmin-4-python-wheel/.
117
$ cat <<EOF \
>lib/python2.7/site-packages/pgadmin4/config_local.py
import os
DATA_DIR = os.path.realpath(
os.path.expanduser(u'~/.pgadmin/'))
LOG_FILE = os.path.join(DATA_DIR, 'pgadmin4.log')
SQLITE_PATH = os.path.join(DATA_DIR, 'pgadmin4.db')
SESSION_DB_PATH = os.path.join(DATA_DIR, 'sessions')
STORAGE_DIR = os.path.join(DATA_DIR, 'storage')
SERVER_MODE = False
EOF
$ cd ~/pgadmin4
$ source bin/activate
$ python \
lib/python2.7/site-packages/pgadmin4/pgAdmin4.py
Features
Connecting to a Server
118
www.dbooks.org
In the Connection tab, enter Host name/address, Port,
Username, and Password. If you don’t want to enter the
password every time, select the Save password check box.
119
Browser
In the left pane, you can see the Browser tree. As you ex-
pand its objects, you can get to the server, which we have
called LOCAL. You can see all the databases it contains:
120
www.dbooks.org
view its columns, integrity constraints, indexes, triggers,
etc.
Running Queries
121
Enter your query in the upper part of the window and
press F5. The Data Output tab in the lower part of the
window will display the result of the query.
You can type the next query starting from a new line,
without deleting the previous query: just select the re-
quired code fragment before pressing F5. Thus, the whole
history of your actions will be always in front of you. It is
usually more convenient than searching for the required
query in the log on the Query History tab.
122
www.dbooks.org
Other
123
Documentation
and Trainings
Reading documentation is indispensable for professional
use of PostgreSQL. It describes all the DBMS features and
provides an exhaustive reference that should always be
at hand. Reading documentation, you can get full and
precise information first hand: it is written by develop-
ers themselves and is carefully kept up-to-date at all
times. PostgreSQL documentation is available at www.
postgresql.org/docs or www.postgrespro.com/docs.
124
www.dbooks.org
Training Courses
125
chapters and requires repeated thoughtful reading. Unlike
documentation, each course consists of separate modules
that offer several related topics, gradually explaining the
subject matter. Instead of providing every possible detail,
they focus on important practical information. Thus, our
courses are intended to complement documentation, not
to replace it.
Topics are split in such a way that theory does not take
more than an hour. Longer time can significantly hinder
course comprehension. Practical assignments usually take
up to 30 minutes.
126
www.dbooks.org
Courses for Database Administrators
Duration: 3 days
Background knowledge:
Topics:
Basic toolkit
1. Installation and management
2. Using psql
3. Configuration
127
Architecture
4. PostgreSQL general overview
5. Isolation and multi-version concurrency control
6. Buffer cache and write-ahead log
Data management
7. Databases and schemas
8. System catalog
9. Tablespaces
10. Low-level details
Administration tasks
11. Monitoring
12. Maintenance
Access control
13. Roles and attributes
14. Privileges
15. Row-level security
16. Connection and authentication
Backups
17. Overview
Replication
18. Overview
128
www.dbooks.org
DBA2. Advanced PostgreSQL administration
Duration: 5 days
Background knowledge:
Topics:
Introduction
1. PostgreSQL Architecture
129
Logging
7. Buffer cache
8. Write-ahead log
9. Checkpoints
Replication
10. File replication
11. Stream replication
12. Switchover to a replica
13. Replication options
Optimization basics
14. Query handling
15. Access paths
16. Join methods
17. Statistics
18. Memory usage
19. Profiling
20. Optimizing queries
Miscellaneous
21. Partitioning
22. Localization
23. Server updates
24. Managing extensions
25. Foreign data
130
www.dbooks.org
Courses for Application Developers
Duration: 4 days
Background knowledge:
SQL fundamentals.
Experience with any procedural programming lan-
guage.
Basic knowledge of Unix.
Topics:
Basic toolkit
1. Installation and management, psql
131
Architecture
2. PostgreSQL general overview
3. Isolation and multi-version concurrency control
4. Buffer cache and write-ahead log
Data management
5. Logical structure
6. Physical structure
“Bookstore” application
7. Application data model
8. Client interaction with DBMS
SQL
9. Functions
10. Composite types
PL/pgSQL
11. Language overview and programming structures
12. Executing queries
13. Cursors
14. Dynamic commands
15. Arrays
16. Error handling
17. Triggers
18. Debugging
Access control
19. Overview
132
www.dbooks.org
DEV2. An advanced course for server-side
developers
Hacking PostgreSQL
Background knowledge:
133
Familiarity with basic structures and algorithms.
Topics:
1. Architecture overview
2. PostgreSQL community and developer tools
3. Extensibility
4. Source code overview
5. Physical data model
6. Shared memory and locks
7. Local process memory
8. Basics of query planner and executor
134
www.dbooks.org
The Hacker’s
Guide to the Galaxy
News and Discussions
135
Mailing Lists
Commitfest
136
www.dbooks.org
community opens “commitfests” for developers to sub-
mit their patches. For example, commitfest 01.03.2017–
31.03.2017 was open for version 10, while the next com-
mitfest 01.09.2017–30.09.2017 is related to the next re-
lease. It allows to stop accepting new features at least
about half a year before the release and have the time to
stabilize the code.
Conferences
137
Postgres Professional
The Postgres Professional company was founded in 2015
by key Russian PostgreSQL developers. It delivers a full
spectrum of PostgreSQL-related services and develops
Postgres Pro, an advanced PostgreSQL fork.
Our address:
Tel:
+7 495 150-06-91
postgrespro.com
138
www.dbooks.org
Services
• Remote DBA.
139
Migration of Application Systems
140
www.dbooks.org
Arranging Trainings
141