Postgre SQLNotes For Professionals
Postgre SQLNotes For Professionals
Email: [email protected]
Select the latest stable (non-Beta) version (9.5.3 at the time of writing). You will most likely want the Win x86-64
package, but if you are running a 32 bit version of Windows, which is common on older computers, select Win
x86-32 instead.
Note: Switching between Beta and Stable versions will involve complex tasks like dump and restore. Upgrading
within beta or stable version only needs a service restart.
You can check if your version of Windows is 32 or 64 bit by going to Control Panel -> System and Security -> System
-> System type, which will say "##-bit Operating System". This is the path for Windows 7, it may be slightly different
on other versions of Windows.
In the installer select the packages you would like to use. For example:
pgAdmin ( https://www.pgadmin.org ) is a free GUI for managing your database and I highly recommend it. In
9.6 this will be installed by default .
PostGIS ( http://postgis.net ) provides geospatial analysis features on GPS coordinates, distances etc. very
popular among GIS developers.
The Language Package provides required libraries for officially supported procedural language PL/Python,
PL/Perl and PL/Tcl.
Other packages like pgAgent, pgBouncer and Slony are useful for larger production servers, only checked as
needed.
All those optional packages can be later installed through "Application Stack Builder".
Note: There are also other non-officially supported language such as PL/V8, PL/Lua PL/Java available.
Open pgAdmin and connect to your server by double clicking on its name, ex. "PostgreSQL 9.5 (localhost:5432).
From this point you can follow guides such as the excellent book PostgreSQL: Up and Running, 2nd Edition (
http://shop.oreilly.com/product/0636920032144.do ).
2
Optional: Manual Service Startup Type
PostgreSQL runs as a service in the background which is slightly different than most programs. This is common for
databases and web servers. Its default Startup Type is Automatic which means it will always run without any input
from you.
Why would you want to manually control the PostgreSQL service? If you're using your PC as a development server
some of the time and but also use it to play video games for example, PostegreSQL could slow down your system a
bit while its running.
Why wouldn't you want manual control? Starting and stopping the service can be a hassle if you do it often.
If you don't notice any difference in speed and prefer avoiding the hassle then leave its Startup Type as Automatic
and ignore the rest of this guide. Otherwise...
Select "Services" from the list, right click on its icon, and select Send To -> Desktop to create a desktop icon for more
convenient access.
Close the Administrative Tools window then launch Services from the desktop icon you just created.
Scroll down until you see a service with a name like postgresql-x##-9.# (ex. "postgresql-x64-9.5").
Right click on the postgres service, select Properties -> Startup type -> Manual -> Apply -> OK. You can change it
back to automatic just as easily.
If you see other PostgreSQL related services in the list such "pgbouncer" or "PostgreSQL Scheduling Agent -
pgAgent" you can also change their Startup Type to Manual because they're not much use if PostgreSQL isn't
running. Although this will mean more hassle each time you start and stop so it's up to you. They don't use as many
resources as PostgreSQL itself and may not have any noticeable impact on your systems performance.
If the service is running its Status will say Started, otherwise it isn't running.
To start it right click and select Start. A loading prompt will be displayed and should disappear on its own soon
after. If it gives you an error try a second time. If that doesn't work then there was some problem with the
installation, possibly because you changed some setting in Windows most people don't change, so finding the
problem might require some sleuthing.
If you ever get an error while attempting to connect to your database check Services to make sure its running.
For other very specific details about the EDB PostgreSQL installation, e.g. the python runtime version in the official
language pack of a specific PostgreSQL version, always refer to the official EBD installation guide , change the
version in link to your installer's major version.
3
readline-devel oder libedit-devel
There are a large number of different options for the configuration of PostgreSQL:
Go into the new created folder and run the cofigure script with the desired options:
./configure --exec=/usr/local/pgsql
For the extension switch the directory cd contrib, run make and make install
4
yum list available | grep postgres*
These are installed with the following command: yum -y install postgresqlXX postgresqlXX-server postgresqlXX-libs
postgresqlXX-contrib
Once installed you will need to start the database service as the service owner (Default is postgres). This is done
with the pg_ctl command.
Debian family
This will install the PostgreSQL server package, at the default version offered by the operating system's package
repositories.
If the version that's installed by default is not the one that you want, you can use the package manager to search
for specific versions which may simultaneously be offered.
You can also use the Yum repository provided by the PostgreSQL project (known as PGDG) to get a different
version. This may allow versions not yet offered by operating system package repositories.
You should get a list that looks something like the following:
In this example, the most recent version of PostgreSQL that is supported in 9.6, so we will install that.
5
sudo port install postgresql96-server postgresql96
The log provides instructions on the rest of the steps for installation, so we do that next.
su postgres -c psql
psql (9.6.1)
Type "help" for help.
6
postgres=#
Here you can type a query to see that the server is running.
setting
------------------------------------------
/opt/local/var/db/postgresql96/defaultdb
(1 row)
postgres=#
Type \q to quit:
postgres=#\q
brew UPDATE
brew install postgresql
Homebrew generally installs the latest stable version. If you need a different one then brew SEARCH postgresql will
list the versions available. If you need PostgreSQL built with particular options then brew info postgresql will list
which options are supported. If you require an unsupported build option, you may have to do the build yourself,
but can still use Homebrew to install the common dependencies.
psql
If psql complains that there's no corresponding database for your user, run CREATEDB.
7
Chapter 2: Data Types
PostgreSQL has a rich set of native data types available to users. Users can add new types to PostgreSQL using the
CREATE TYPE command.
https://www.postgresql.org/docs/9.6/static/datatype.html
8
Section 2.3: Geometric Types
Name Storage Size Description Representation
point 16 bytes Point on a plane (x,y)
line 32 bytes Infinite line {A,B,C}
lseg 32 bytes Finite line segment ((x1,y1),(x2,y2))
BOX 32 bytes Rectangular box ((x1,y1),(x2,y2))
path 16+16n bytes Closed path (similar to polygon) ((x1,y1),...)
path 16+16n bytes Open path [(x1,y1),...]
polygon 40+16n bytes Polygon (similar to closed path) ((x1,y1),...)
CIRCLE 24 bytes Circle <(x,y),r> (center point and radius)
Declaring an Array
SELECT INTEGER[];
SELECT INTEGER[3];
SELECT INTEGER[][];
SELECT INTEGER[3][3];
SELECT INTEGER ARRAY;
SELECT INTEGER ARRAY[3];
Creating an Array
SELECT '{0,1,2}';
SELECT '{{0,1},{1,2}}';
SELECT ARRAY[0,1,2];
SELECT ARRAY[ARRAY[0,1],ARRAY[1,2]];
Accessing an Array
By default PostgreSQL uses a one-based numbering convention for arrays, that is, an array of n elements starts
with ARRAY[1] and ends with ARRAY[n].
9
WITH arr AS (SELECT ARRAY[0,1,2] int_arr) SELECT int_arr[1] FROM arr;
int_arr
---------
0
(1 ROW)
--sclicing an array
WITH arr AS (SELECT ARRAY[0,1,2] int_arr) SELECT int_arr[1:2] FROM arr;
int_arr
---------
{0,1}
(1 ROW)
array_dims
------------
[1:3]
(1 ROW)
array_length
--------------
3
(1 ROW)
cardinality
-------------
3
(1 ROW)
Array functions
will be added
10
Chapter 3: Dates, Timestamps, and
Intervals
Section 3.1: SELECT the last day of month
You can select the last day of month.
This statement will produce the string "12 Aug 2016 04:40:32PM". The formatting string can be modified in many
different ways; the full list of template patterns can be found here.
Note that you can also insert plain text into the formatting string and you can use the template patterns in any
order:
This will produce the string "Today is Saturday, the 12th day of the month of August of 2016". You should keep in
mind, though, that any template patterns - even the single letter ones like "I", "D", "W" - are converted, unless the
plain text is in double quotes. As a safety measure, you should put all plain text in double quotes, as done above.
You can localize the string to your language of choice (day and month names) by using the TM (translation mode)
modifier. This option uses the localization setting of the server running PostgreSQL or the client connecting to it.
With a Spanish locale setting this produces "Sábado, 12 de Agosto del año 2016".
11
Chapter 4: Table Creation
Section 4.1: Show table definition
Open the psql command line tool connected to the database where your table is. Then type the following
command:
\d tablename
\d+ tablename
If you have forgotten the name of the table, just type \d into psql to obtain a list of tables and views in the current
database.
CREATE TABLE people_over_30 AS SELECT * FROM person WHERE age > 30;
12
);
Alternatively, you can place the PRIMARY KEY constraint directly in the column definition:
It is recommended that you use lower case names for the table and as well as all the columns. If you use upper
case names such as Person you would have to wrap that name in double quotes ("Person") in each and every
query because PostgreSQL enforces case folding.
13
Chapter 5: SELECT
Section 5.1: SELECT using WHERE
In this topic we will base on this table of users :
+----+------------+-----------+----------+------+
| id | first_name | last_name | username | pass |
+----+------------+-----------+----------+------+
| 1 | hello | world | hello | word |
+----+------------+-----------+----------+------+
| 2 | root | me | root | toor |
+----+------------+-----------+----------+------+
Syntax
Examples
14
Chapter 6: Find String Length / Character
Length
To get length of "character varying", "text" fields, Use char_length() or character_length().
Result:
Result:
15
Chapter 7: COALESCE
Coalesce returns the first none null argument from a set of arguments. Only the first non null argument is return,
all subsequent arguments are ignored. The function will evaluate to null if all arguments are null.
COALESCE
--------
'HELLO WORLD'
coalesce
--------
'first non null'
COALESCE
--------
16
Chapter 8: INSERT
Section 8.1: Insert data using COPY
COPY is PostgreSQL's bulk-insert mechanism. It's a convenient way to transfer data between files and tables, but it's
also far faster than INSERT when adding more than a few thousand rows at a time.
1,Yogesh
2,Raunak
3,Varun
4,Kamal
5,Hari
6,Amit
And we need a two column table into which this data can be imported into.
Now the actual copy operation, this will create six records in the table.
id | name
----+--------
1 | Yogesh
3 | Varun
5 | Hari
7 | Amol
2 | Raunak
4 | Kamal
6 | Amit
8 | Amar
17
Section 8.2: Inserting multiple rows
You can insert multiple rows in the database at the same time:
If you want to insert data into my_table and get the id of that row:
Above query will return the id of the row where the new record was inserted.
The most basic insert involves inserting all values in the table:
INSERT INTO person VALUES (1, 'john doe', 25, 'new york');
If you want to insert only specific columns, you need to explicitly indicate which columns:
Note that if any constraints exist on the table , such as NOT NULL, you will be required to include those columns in
either case.
18
INSERT INTO person SELECT * FROM tmp_person WHERE age < 30;
Note that the projection of the select must match the columns required for the insert. In this case, the tmp_person
table has the same columns as person.
Say you have a table called my_table, created in several previous examples. We insert a row, returning PK value of
inserted row:
INSERT 0 1
Now if we try to insert row with existing unique key it will raise an exception:
b=# INSERT INTO my_table values (2,'one',333) ON CONFLICT (id) DO UPDATE SET name =
my_table.name||' changed to: "two" at '||now() returning *;
id | name | contact_number
----+---------------------------------------------------------------------------------------------
--------------+----------------
2 | one changed to: "two" at 2016-11-23 08:32:17.105179+00 | 333
(1 row)
INSERT 0 1
19
postgres=# \! cat my_table.txt
c1|c2|c3
1|1|1
2|2|2
3|3|3
4|4|4
5|5|null_string
20
Chapter 9: UPDATE
Section 9.1: Updating a table based on joining another table
You can also update data in a table based on data from another table:
UPDATE person
SET state_code = cities.state_code
FROM cities
WHERE cities.city = city;
Here we are joining the person city column to the cities city column in order to get the city's state code. This is
then used to update the state_code column in the person table.
UPDATE person
SET country = 'USA',
state = 'NY'
WHERE city = 'New York';
21
Chapter 10: JSON Support
JSON - Java Script Object Notation , Postgresql support JSON Data type since 9.2 version. There are some predefined
function and operators to access the JSON data. The -> operator returns the key of JSON column. The ->> operator
returns the value of JSON Column.
Populating the DB
INSERT INTO books(client, DATA) VALUES (
'Joe',
'{ "title": "Siddhartha", "author": { "first_name": "Herman", "last_name": "Hesse" } }'
),(
'Jenny',
'{ "title": "Dharma Bums", "author": { "first_name": "Jack", "last_name": "Kerouac" } }'
),(
'Jenny',
'{ "title": "100 años de soledad", "author": { "first_name": "Gabo", "last_name": "Marquéz" }
}'
);
Output:
Selecting 1 column:
SELECT client,
DATA->'title' AS title
FROM books;
Output:
22
Selecting 2 columns:
SELECT client,
DATA->'title' AS title, DATA->'author' AS author
FROM books;
Output:
-> vs ->>
The -> operator returns the original JSON type (which might be an object), whereas ->> returns text.
You can use the -> to return a nested object and thus chain the operators:
SELECT client,
DATA->'author'->'last_name' AS author
FROM books;
Output:
Filtering
SELECT
client,
DATA->'title' AS title
FROM books
WHERE DATA->'title' = '"Dharma Bums"';
Output:
23
Nested filtering
SELECT
client,
DATA->'title' AS title
FROM books
WHERE DATA->'author'->>'last_name' = 'Kerouac';
Output:
We’re going to store events in this table, like pageviews. Each event has properties, which could be anything (e.g.
current page) and also sends information about the browser (like OS, screen resolution, etc). Both of these are
completely free form and could change over time (as we think of extra stuff to track).
24
Now lets select everything:
Output:
Using the JSON operators, combined with traditional PostgreSQL aggregate functions, we can pull out whatever we
want. You have the full might of an RDBMS at your disposal.
Output:
Output:
Output:
25
Section 10.2: Querying complex JSON documents
Taking a complex JSON document in a table:
26
Performance of @> compared to -> and ->>
It is important to understand the performance difference between using @>, -> and ->> in the WHERE part of the
query. Although these two queries appear to be broadly equivalent:
the first statement will use the index created above whereas the latter two will not, requiring a complete table scan.
It is still allowable to use the -> operator when obtaining resultant data, so the following queries will also use the
index:
At this point you can insert data in to the table and query it efficiently.
27
Chapter 11: Aggregate Functions
Section 11.1: Simple statistics: min(), max(), avg()
In order to determine some simple statistics of a value in a column of a table, you can use an aggregate function.
Name Age
Allie 17
Amanda 14
Alana 20
You could write this statement to get the minimum, maximum and average value:
Result:
All memory leak candidates will have a trend of consuming more memory as more time passes. If you plot this
trend, you would imagine a line going up and to the left:
^
|
s | Legend:
i | * - data point
z | -- - trend
e |
( |
b | *
y | --
t | --
e | * -- *
s | --
) | *-- *
| -- *
| -- *
--------------------------------------->
time
Suppose you have a table containing heap dump histogram data (a mapping of classes to how much memory they
consume):
28
CREATE TABLE heap_histogram (
-- when the heap histogram was taken
histwhen TIMESTAMP WITHOUT TIME ZONE NOT NULL,
-- the object type bytes are referring to
-- ex: java.util.String
CLASS CHARACTER VARYING NOT NULL,
-- the size in bytes used by the above class
bytes INTEGER NOT NULL
);
To compute the slope for each class, we group by over the class. The HAVING clause > 0 ensures that we get only
candidates with a positive slop (a line going up and to the left). We sort by the slope descending so that we get the
classes with the largest rate of memory increase at the top.
Output:
class | slope
---------------------------+----------------------
java.util.ArrayList | 71.7993806279174
java.util.HashMap | 49.0324576155785
java.lang.String | 31.7770770326123
joe.schmoe.BusinessObject | 23.2036817108056
java.lang.ThreadLocal | 20.9013528767851
From the output we see that java.util.ArrayList's memory consumption is increasing the fastest at 71.799 bytes per
second and is potentially part of the memory leak.
You could write SELECT ... GROUP BY statement to get names from each country:
Note that you need to use a GROUP BY clause because STRING_AGG() is an aggregate function.
Result:
29
names country
Allie, Amanda USA
Alana Russia
30
Chapter 12: Common Table Expressions
(WITH)
Section 12.1: Common Table Expressions in SELECT Queries
Common table expressions support extracting portions of larger queries. For example:
WITH sales AS (
SELECT
orders.ordered_at,
orders.user_id,
SUM(orders.amount) AS total
FROM orders
GROUP BY orders.ordered_at, orders.user_id
)
SELECT
sales.ordered_at,
sales.total,
users.NAME
FROM sales
JOIN users USING (user_id)
31
Chapter 13: Window Functions
Section 13.1: generic example
Preparing data:
Running:
SELECT *
, DENSE_RANK() OVER (ORDER BY i) dist_by_i
, LAG(t) OVER () prev_t
, NTH_VALUE(i, 6) OVER () nth
, COUNT(TRUE) OVER (PARTITION BY i) num_by_i
, COUNT(TRUE) OVER () num_all
, NTILE(3) over() ntile
FROM wf_example
;
Result:
Explanation:
dist_by_i: DENSE_RANK() OVER (ORDER BY i) is like a row_number per distinct values. Can be used for the number
of distinct values of i (COUNT(DISTINCT i) wold not work). Just use the maximum value.
prev_t: LAG(t) OVER () is a previous value of t over the whole window. mind that it is null for the first row.
nth: NTH_VALUE(i, 6) OVER () is the value of sixth rows column i over the whole window
ntile: NTILE(3) over() splits the whole window to 3 (as much as possible) equal in quantity parts
32
Section 13.2: column values vs dense_rank vs rank vs
row_number
here you can find the functions.
SELECT i
, DENSE_RANK() OVER (ORDER BY i)
, ROW_NUMBER() OVER ()
, RANK() OVER (ORDER BY i)
FROM wf_example
dense_rank orders VALUES of i by appearance in window. i=1 appears, so first row has dense_rank, next and
third i value does not change, so it is dense_rank shows 1 - FIRST value not changed. fourth row i=2, it is
second value of i met, so dense_rank shows 2, andso for the next row. Then it meets value i=3 at 6th row, so
it show 3. Same for the rest two values of i. So the last value of dense_rank is the number of distinct values of
i.
rank Not to confuse with dense_rank this function orders ROW NUMBER of i values. So it starts same with
three ones, but has next value 4, which means i=2 (new value) was met at row 4. Same i=3 was met at row 6.
Etc..
33
Chapter 14: Recursive queries
There are no real recursive querys!
34
Chapter 15: Programming with PL/pgSQL
Section 15.1: Basic PL/pgSQL Function
A simple PL/pgSQL function:
This could have been achieved with just the SQL statement but demonstrates the basic structure of a function.
SELECT active_subscribers();
calling:
t=# DO
$$
DECLARE
_t TEXT;
BEGIN
35
perform s165();
exception WHEN SQLSTATE 'P0001' THEN raise info '%','state P0001 caught: '||SQLERRM;
perform s164();
END;
$$
;
INFO: state P0001 caught: NOTHING specified
ERROR: S 164
DETAIL: D 164
HINT: H 164
CONTEXT: SQL STATEMENT "SELECT s164()"
PL/pgSQL FUNCTION inline_code_block line 7 AT PERFORM
here custom P0001 processed, and P2222, not, aborting the execution.
Also it makes huge sense to keep a table of exceptions, like here: http://stackoverflow.com/a/2700312/5315974
36
Chapter 16: Inheritance
Section 16.1: Creating children tables
CREATE TABLE users (username TEXT, email TEXT);
CREATE TABLE simple_users () INHERITS (users);
CREATE TABLE users_with_password (PASSWORD TEXT) INHERITS (users);
users
Column Type
username text
email text
simple_users
Column Type
username text
email text
users_with_password
Column Type
username text
email text
password text
37
Chapter 17: Export PostgreSQL database
table header and data to CSV file
From Adminer management tool it's has export to csv file option for mysql database But not available for
postgresql database. Here I will show the command to export CSV for postgresql database.
38
Chapter 18: Triggers and Trigger Functions
The trigger will be associated with the specified table or view and will execute the specified function function_name
when certain events occur.
FOR EACH ROW is called once for every row that the operation modifies;
FOR EACH STATEMENT is called onde for any given operation.
Step 3: test it
INSERT INTO company (NAME) VALUES ('My company');
SELECT * FROM company;
39
CREATE OR REPLACE FUNCTION add_log_function()
RETURNS TRIGGER AS $BODY$
DECLARE
vDescription TEXT;
vId INT;
vReturn RECORD;
BEGIN
vDescription := TG_TABLE_NAME || ' ';
IF (TG_OP = 'INSERT') THEN
vId := NEW.id;
vDescription := vDescription || 'added. Id: ' || vId;
vReturn := NEW;
ELSIF (TG_OP = 'UPDATE') THEN
vId := NEW.id;
vDescription := vDescription || 'updated. Id: ' || vId;
vReturn := NEW;
ELSIF (TG_OP = 'DELETE') THEN
vId := OLD.id;
vDescription := vDescription || 'deleted. Id: ' || vId;
vReturn := OLD;
END IF;
RETURN vReturn;
END $BODY$
LANGUAGE plpgsql;
Step 3: test it
INSERT INTO company (NAME) VALUES ('Company 1');
INSERT INTO company (NAME) VALUES ('Company 2');
INSERT INTO company (NAME) VALUES ('Company 3');
UPDATE company SET NAME='Company new 2' WHERE NAME='Company 2';
DELETE FROM company WHERE NAME='Company 1';
SELECT * FROM log;
BEGIN
-- TG_TABLE_NAME :name of the table that caused the trigger invocation
40
IF (TG_TABLE_NAME = 'users') THEN
END IF;
RETURN NULL;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
41
Chapter 19: Event Triggers
Event Triggers will be fired whenever event associated with them occurs in database.
DDL_COMMAND_START
DDL_COMMAND_END
SQL_DROP
This is example for creating an Event Trigger and logging DDL_COMMAND_START events.
42
Chapter 20: Role Management
Section 20.1: Create a user with a password
Generally you should avoid using the default database role (often postgres) in your application. You should instead
create a user with lower levels of privileges. Here we make one called niceusername and give it a password very-
strong-PASSWORD
The problem with that is that queries typed into the psql console get saved in a history file .psql_history in the
user's home directory and may as well be logged to the PostgreSQL database server log, thus exposing the
password.
To avoid this, use the \PASSWORD command to set the user password. If the user issuing the command is a
superuser, the current password will not be asked. (Must be superuser to alter passwords of superusers)
--ACCESS DB
REVOKE CONNECT ON DATABASE nova FROM PUBLIC;
GRANT CONNECT ON DATABASE nova TO USER;
With the above queries, untrusted users can no longer connect to the database.
--ACCESS SCHEMA
REVOKE ALL ON SCHEMA public FROM PUBLIC;
GRANT USAGE ON SCHEMA public TO USER;
The next set of queries revoke all privileges from unauthenticated users and provide limited set of privileges for the
read_write user.
--ACCESS TABLES
REVOKE ALL ON ALL TABLES IN SCHEMA public FROM PUBLIC ;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only ;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO read_write ;
GRANT ALL ON ALL TABLES IN SCHEMA public TO ADMIN ;
--ACCESS SEQUENCES
REVOKE ALL ON ALL SEQUENCES IN SCHEMA public FROM PUBLIC;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO read_only; -- allows the use of CURRVAL
GRANT UPDATE ON ALL SEQUENCES IN SCHEMA public TO read_write; -- allows the use of NEXTVAL and
SETVAL
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO read_write; -- allows the use of CURRVAL and
NEXTVAL
GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO ADMIN;
43
Section 20.3: Create Role and matching database
To support a given application, you often create a new role and database to match.
$ CREATEUSER -P blogger
Enter PASSWORD FOR the NEW ROLE: ********
Enter it again: ********
This assumes that pg_hba.conf has been properly configured, which probably looks like this:
2. Set search_path with ALTER USER command to append a new schema my_schema
Alternative:
44
Section 20.5: Create Read Only User
CREATE USER readonly WITH ENCRYPTED PASSWORD 'yourpassword';
GRANT CONNECT ON DATABASE <database_name> TO readonly;
With below queries, you can set access privileges on objects created in the future in specified schema.
Or, you can set access privileges on objects created in the future by specified user.
ALTER DEFAULT PRIVILEGES FOR ROLE ADMIN GRANT SELECT ON TABLES TO read_only;
45
Chapter 21: Postgres cryptographic
functions
In Postgres, cryptographic functions can be unlocked by using pgcrypto module. CREATE EXTENSION pgcrypto;
Examples:
46
Chapter 22: Comments in PostgreSQL
COMMMENT main purpose is to define or change a comment on database object.
Only a single comment(string) can be given on any database object. COMMENT will help us to know what for the
particular database object has been defined whats its actual purpose is.
The rule for COMMENT ON ROLE is that you must be superuser to comment on a superuser role, or have the
CREATEROLE privilege to comment on non-superuser roles. Of course, a superuser can comment on anything
47
Chapter 23: Backup and Restore
Section 23.1: Backing up one database
pg_dump -Fc -f DATABASE.pgsql DATABASE
The -Fc selects the "custom backup format" which gives you more power than raw SQL; see pg_restore for more
details. If you want a vanilla SQL file, you can do this instead:
or even
A safer alternative uses -1 to wrap the restore in a transaction. The -f specifies the filename rather than using shell
redirection.
Custom format files must be restored using pg_restore with the -d option to specify the database:
Usage of the custom format is recommended because you can choose which things to restore and optionally
enable parallel processing.
You may need to do a pg_dump followed by a pg_restore if you upgrade from one postgresql release to a newer
one.
This works behind the scenes by making multiple connections to the server once for each database and executing
pg_dump on it.
Sometimes, you might be tempted to set this up as a cron job, so you want to see the date the backup was taken as
part of the filename:
$ postgres-backup-$(DATE +%Y-%m-%d).sql
48
The output from pg_dumpall is sufficient to restore to an identically-configured Postgres instance, but the
configuration files in $PGDATA (pg_hba.conf and postgresql.conf) are not part of the backup, so you'll have to back
them up separately.
To take a filesystem backup, you must use these functions to help ensure that Postgres is in a consistent state while
the backup is prepared.
psql -p 5432 -U postgres -d test_database -A -F, -c "select * from user" > /home/USER/user_data.CSV
-F is to specify delimiter
-A OR --no-align
Switches to unaligned output mode. (The default output mode is otherwise aligned.)
To insert into table USER from a file named user_data.CSV placed inside /home/USER/:
Note: In absence of the option WITH DELIMITER, the default delimiter is comma ,
Note: If data is quoted, by default data quoting characters are double quote. If the data is quoted using any other
character use the QUOTE option; however, this option is allowed only when using CSV format.
49
Section 23.6: Using Copy to export
To Copy table to standard o/p
COPY <tablename> TO STDOUT (DELIMITER '|');
50
Chapter 24: Backup script for a production
DB
parameter details
save_db The main backup directory
dbProd The secondary backup directory
DATE The date of the backup in the specified format
dbprod The name of the database to be saved
/opt/postgres/9.0/bin/pg_dump The path to the pg_dump binary
Specifies the host name of the machine on which the server is running, Example :
-h
localhost
Specifies the TCP port or local Unix domain socket file extension on which the
-p
server is listening for connections, Example 5432
-U User name to connect as.
#!/bin/sh
cd /save_db
#rm -R /save_db/*
DATE=$(date +%d-%m-%Y-%Hh%M)
echo -e "Sauvegarde de la base du ${DATE}"
mkdir prodDir${DATE}
cd prodDir${DATE}
#dump file
/opt/postgres/9.0/bin/pg_dump -i -h localhost -p 5432 -U postgres -F c -b -w -v -f
"dbprod${DATE}.backup" dbprod
#SQL file
/opt/postgres/9.0/bin/pg_dump -i -h localhost -p 5432 -U postgres --format plain --verbose -f
"dbprod${DATE}.sql" dbprod
51
Chapter 25: Accessing Data
Programmatically
Section 25.1: Accessing PostgreSQL with the C-API
The C-API is the most powerful way to access PostgreSQL and it is surprisingly comfortable.
During compilation, you have to add the PostgreSQL include directory, which can be found with pg_config --
includedir, to the include path.
You must link with the PostgreSQL client shared library (libpq.so on UNIX, libpq.dll on Windows). This library is
in the PostgreSQL library directory, which can be found with pg_config --libdir.
Note: For historical reason, the library is called libpq.soand not libpg.so, which is a popular trap for beginners.
Given that the below code sample is in file coltype.c, compilation and linking would be done with
with the GNU C compiler (consider adding -Wl,-rpath,"$(pg_config --libdir)" to add the library search path) or
with
Sample program
/* necessary for all PostgreSQL client programs, should be first */
#include <libpq-fe.h>
#include <stdio.h>
#include <string.h>
#ifdef TRACE
#define TRACEFILE "trace.out"
#endif
/*
* Using an empty connectstring will use default values for everything.
* If set, the environment variables PGHOST, PGDATABASE, PGPORT and
* PGUSER will be used.
*/
conn = PQconnectdb("");
52
/*
* This can only happen if there is not enough memory
* to allocate the PGconn structure.
*/
if (conn == NULL)
{
fprintf(stderr, "Out of memory connecting to PostgreSQL.\n");
return 1;
}
#ifdef TRACE
if (NULL == (trc = fopen(TRACEFILE, "w")))
{
fprintf(stderr, "Error opening trace file \"%s\"!\n", TRACEFILE);
PQfinish(conn);
return 1;
}
53
/* SQL statement should return results */
if (PGRES_TUPLES_OK != PQresultStatus(res))
{
fprintf(stderr, "%s\n", PQerrorMessage(conn));
PQfinish(conn);
#ifdef TRACE
fclose(trc);
#endif
return 1;
}
printf(PQfname(res, j));
}
printf("\n\n");
printf(PQgetvalue(res, i, j));
}
printf("\n");
}
54
Section 25.2: Accessing PostgreSQL from python using
psycopg2
You can find description of the driver here.
import psycopg2
db_host = 'postgres.server.com'
db_port = '5432'
db_un = 'user'
db_pw = 'password'
db_name = 'testdb'
print(cur.fetchall())
Will result:
A typical query is performed by creating a command, binding parameters, and then executing the command. In C#:
conn.Open();
// Create a new command with CommandText and Connection constructor
using (var cmd = new NpgsqlCommand(querystring, conn))
{
// Add a parameter and set its type with the NpgsqlDbType enum
var contentString = "Hello World!";
cmd.Parameters.Add("@content", NpgsqlDbType.Text).Value = contentString;
/* It is possible to reuse a command object and open connection instead of creating new ones
*/
55
int keyId = 101;
cmd.CommandText = "SELECT primary_key, some_field FROM data WHERE primary_key = @keyId";
cmd.Parameters.Clear();
cmd.Parameters.Add("@keyId", NpgsqlDbType.Integer).Value = keyId;
// Execute the command and read through the rows one by one
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read()) // Returns false for 0 rows, or after reading the last row of
the results
{
// read an integer value
int primaryKey = reader.GetInt32(0);
// or
primaryKey = Convert.ToInt32(reader["primary_key"]);
Assuming, Pomm has been installed using composer, here is a complete example:
<?php
use PommProject\Foundation\Pomm;
$loader = require __DIR__ . '/vendor/autoload.php';
$pomm = new Pomm(['my_db' => ['dsn' => 'pgsql://user:pass@host:5432/db_name']]);
// TABLE comment (
// comment_id uuid PK, created_at timestamptz NN,
// is_moderated bool NN default false,
// content text NN CHECK (content !~ '^\s+$'), author_email text NN)
$sql = <<<SQL
SELECT
comment_id,
created_at,
is_moderated,
content,
author_email
FROM comment
INNER JOIN author USING (author_email)
WHERE
age(now(), created_at) < $*::interval
ORDER BY created_at ASC
SQL;
if ($comments->isEmpty()) {
printf("There are no new comments since yesterday.");
} else {
56
foreach ($comments as $comment) {
printf(
"%s has posted at %s. %s\n",
$comment['author_email'],
$comment['created_at']->format("Y-m-d H:i:s"),
$comment['is_moderated'] ? '[OK]' : '');
}
}
Pomm’s query manager module escapes query arguments to prevent SQL injection. When the arguments are cast,
it also converts them from a PHP representation to valid Postgres values. The result is an iterator, it uses a cursor
internally. Every row is converted on the fly, booleans to booleans, timestamps to \DateTime etc.
57
Chapter 26: Connect to PostgreSQL from
Java
The API to use a relational database from Java is JDBC.
To use it, put the JAR-file with the driver on the JAVA class path.
This documentation shows samples how to use the JDBC driver to connect to a database.
First, the driver has to be registered with java.sql.DriverManager so that it knows which class to use.
This is done by loading the driver class, typically with java.lang.CLASS.forname(;driver class name>).
/**
* Connect to a PostgreSQL database.
* @param url the JDBC URL to connect to; must start with "jdbc:postgresql:"
* @param user the username for the connection
* @param password the password for the connection
* @return a connection object for the established connection
* @throws ClassNotFoundException if the driver class cannot be found on the Java class path
* @throws java.sql.SQLException if the connection to the database fails
*/
private static java.sql.Connection connect(String url, String user, String password)
throws ClassNotFoundException, java.sql.SQLException
{
/*
* Register the PostgreSQL JDBC driver.
* This may throw a ClassNotFoundException.
*/
Class.forName("org.postgresql.Driver");
/*
* Tell the driver manager to connect to the database specified with the URL.
* This may throw an SQLException.
*/
return java.sql.DriverManager.getConnection(url, user, password);
}
Not that user and password can also be included in the JDBC URL, in which case you don't have to specify them in
the getConnection method call.
/**
* Connect to a PostgreSQL database.
* @param url the JDBC URL to connect to. Must start with "jdbc:postgresql:"
* @param user the username for the connection
* @param password the password for the connection
58
* @return a connection object for the established connection
* @throws ClassNotFoundException if the driver class cannot be found on the Java class path
* @throws java.sql.SQLException if the connection to the database fails
*/
private static java.sql.Connection connect(String url, String user, String password)
throws ClassNotFoundException, java.sql.SQLException
{
/*
* Register the PostgreSQL JDBC driver.
* This may throw a ClassNotFoundException.
*/
Class.forName("org.postgresql.Driver");
java.util.Properties props = new java.util.Properties();
props.setProperty("user", user);
props.setProperty("password", password);
/* don't use server prepared statements */
props.setProperty("prepareThreshold", "0");
/*
* Tell the driver manager to connect to the database specified with the URL.
* This may throw an SQLException.
*/
return java.sql.DriverManager.getConnection(url, props);
}
/**
* Create a data source with connection pool for PostgreSQL connections
* @param url the JDBC URL to connect to. Must start with "jdbc:postgresql:"
* @param user the username for the connection
* @param password the password for the connection
* @return a data source with the correct properties set
*/
private static javax.sql.DataSource createDataSource(String url, String user, String password)
{
/* use a data source with connection pooling */
org.postgresql.ds.PGPoolingDataSource ds = new org.postgresql.ds.PGPoolingDataSource();
ds.setUrl(url);
ds.setUser(user);
ds.setPassword(password);
/* the connection pool will have 10 to 20 connections */
ds.setInitialConnections(10);
ds.setMaxConnections(20);
/* use SSL connections without checking server certificate */
ds.setSslMode("require");
ds.setSslfactory("org.postgresql.ssl.NonValidatingFactory");
return ds;
}
Once you have created a data source by calling this function, you would use it like this:
59
/* do some work */
60
Chapter 27: PostgreSQL High Availability
Section 27.1: Replication in PostgreSQL
Configuring the Primary Server
Requirements:
mkdir $PGDATA/archive
This is host base authentication file, contains the setting for client autherntication. Add below entry:
wal_level = hot_standby
`hot_standby` logs what IS required TO accept READ ONLY queries ON slave SERVER.
archive_mode=ON
This parameters allows to send WAL segments to archive location using archive_command parameter.
Basically what above archive_command does is it copies the WAL segments to archive directory.
61
Backing up the primay server to the slave server
Important: Don't start the service again until all configuration and backup steps are complete. You must
bring up the standby server in a state where it is ready to be a backup server. This means that all
configuration settings must be in place and the databases must be already synchronized. Otherwise,
streaming replication will fail to start`
pg_basebackup utility copies the data from primary server data directory to slave data directory.
-h: Specifies the SYSTEM WHERE TO look FOR the PRIMARY SERVER
-xlog-method=stream: This will FORCE the pg_basebackup TO open another CONNECTION AND stream
enough xlog WHILE backup IS running.
It ALSO ensures that fresh backup can be started WITHOUT failing back TO
USING an archive.
To configure the standby server, you'll edit postgresql.conf and create a new configuration file named
recovery.conf.
hot_standby = ON
This specifies whether you are allowed to run queries while recovering
standby_mode = ON
Set the connection string to the primary server. Replace with the external IP address of the primary
server. Replace with the password for the user named replication
trigger_file = '/tmp/postgresql.trigger.5432'
The trigger_file path that you specify is the location where you can add a file when you want the
system to fail over to the standby server. The presence of the file "triggers" the failover. Alternatively,
you can use the pg_ctl promote command to trigger failover.
62
Start the standby server
You now have everything in place and are ready to bring up the standby server
63
Chapter 28: EXTENSION dblink and
postgres_fdw
Section 28.1: Extention FDW
FDW is an implimentation of dblink it is more helpful, so to use it:
1. Create an extention:
2. Create SERVER:
CREATE SERVER name_srv FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host 'hostname',
dbname 'bd_name', port '5432');
CREATE USER MAPPING FOR postgres SERVER name_srv OPTIONS(USER 'postgres', PASSWORD 'password');
1. Create EXTENSION :
2. Create SERVER :
CREATE SERVER server_name FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host 'host_ip',
dbname 'db_name', port 'port_number');
64
5. Import server schema:
For exemple Select some attribute from another table in another database:
SELECT * FROM
dblink ('dbname = bd_distance port = 5432 host = 10.6.6.6 user = username
password = passw@rd', 'SELECT id, code FROM schema.table')
AS newTable(id INTEGER, code CHARACTER VARYING);
65
Chapter 29: Postgres Tip and Tricks
Section 29.1: DATEADD alternative in Postgres
SELECT CURRENT_DATE + '1 day'::INTERVAL
SELECT '1999-12-11'::TIMESTAMP + '19 days'::INTERVAL
SELECT '1 month'::INTERVAL + '1 month 3 days'::INTERVAL
SELECT
(
(DATE_PART('year', AgeonDate) - DATE_PART('year', tmpdate)) * 12
+
(DATE_PART('month', AgeonDate) - DATE_PART('month', tmpdate))
)
FROM dbo."Table1"
66
Yearwise difference between two dates(timestamp)
Then
INSERT INTO
<SCHEMA_NAME>.<TABLE_NAME_1>
SELECT *
FROM
DBLINK(
'HOST=<IP-ADDRESS> USER=<USERNAME> PASSWORD=<PASSWORD> DBNAME=<DATABASE>',
'SELECT * FROM <SCHEMA_NAME>.<TABLE_NAME_2>')
AS <TABLE_NAME>
(
<COLUMN_1> <DATATYPE_1>,
<COLUMN_1> <DATATYPE_2>,
<COLUMN_1> <DATATYPE_3>
);
67