lk/data/sql/postgresql.md
2020-10-06 19:54:13 +02:00

6.8 KiB

Setup

Install postgres and start it as a service, then start with:

psql

Arch setup

su -l postgres

initdb -D /var/lib/postgres/data

Make a database as the new user postgres

sudo su postgres

[postgres] echo $HOME

[postgres]

[postgres] CREATE DATABASE dvdrental;

Sample Data

Get sample data.

wget http://www.postgresqltutorial.com/wp-content/uploads/2019/05/dvdrental.zip

And then get the pdf mapping the sample data:

wget http://www.postgresqltutorial.com/wp-content/uploads/2018/03/printable-postgresql-sample-database-diagram.pdf

Unzip and load sample data:

unzip dvdrental.zip

sudo su postgres

[postgres] $ pg_restore -U postgres -d dvdrental dvdrental.tar

[postgres]

Commands

Basics

List available databases.

\l

You'll see a list of available databases like:

dnd

dvdrentals

Then you can connect to one:

\c dvdrental

And have a look at what tables it has:

\d dvdrental

If it has tables such as language, film_actor and inventory, you can see the table's settings with:

\dt film_actor

And pull back the entire table:

SELECT * from film_actor;

Various

Connect to 231.13.48.38 with user 'bob', port 1234, database 'X'

psql -h 231.13.48.38 -p1234 -U bob X

Setup Yourself

Make database "test" and connect to it.

CREATE DATABASE test;

\l test

Delete database 'dogs':

DROP DATABASE dogs;

Making a table has a basic form of:

CREATE TABLE table_name (

then [ column name ] + [data type ] ... (and possibly data constraints)

)

Data Types Meaning Constraints
BIGSERIAL A number incrementing by one each entry 'NOT NULL PRIMARY KEY (so it's used for relational reference)
int integer (50) limits the table to 50, e.g. int(50)
VARCHAR any characters limit, e.g.VARCHAR(70)
TIMESTAMP time
date date
text text?
tsquery text search query
money money
json textual JSON data
cidr ipv4 or 6 address
macaddr mac address

E.g.

CREATE TABLE character (
id int,
str int(1),
dex int(1),
spd int(1),
int int(1),
wts int(1),
cha int(1));

See your table:

\d

Look at what columns you have there:

\d character

But this allows for empty characters, so...


CREATE TABLE person (
	id BIGSERIAL NOT NULL PRIMARY KEY,
	first_name VARCHAR(50) NOT NULL,
	last_name VARCHAR(50) NOT NULL,
	last_name VARCHAR(50) NOT NULL,
	gender VARCHAR(7) NOT NULL,
	date_of_birth DATE NOT NULL,
);

Delete with

DROP TABLE person;

Inserting Data


INSERT INTO person (
	first_name,
	last_name,
	gender,
	date_of_birth)
VALUES ('Hugi','Smith','DWARF', date '200-01-12');

Selecting Data

You can also mass select by choosing to insert a file. Download example data here.

\i /home/ghost/file.sql

Various querries:

SELECT * FROM person;

SELECT * FROM person ORDER BY id DESC;

SELECT * FROM person

Offset, Fetch and Limit

'Limit' is not official, but was accepted later:

SELECT * FROM person ORDER BY country ASC LIMIT 10;

The official way to make a limit is 'FIRST 5 ROWS ONLY:

SELECT * FROM person OFFSET 5 FETCH FIRST 5 ROWS ONLY;

SELECT * FROM person where gender = 'Male' AND ( country_of_birth = 'Poland' OR country_of_birth = 'China');

Miss out the first 5 result with 'OFFSET 5'.

SELECT p* FROM PERSON WHERE gender = 'Female' AND country_of_birth = 'Kosovo' OFFSET 5;

SELECT * FROM person OFFSET 5 FETCH FIRST 7 ROW ONLY;

Advanced Selection

This query takes a lot of typing:

SELECT * FROM person WHERE country_of_birth = 'China' OR country_of_birth = 'Kosovo' OR country_of_birth = 'Brazil';

You can write the same thing with less typing:

SELECT * FROM person WHERE country_of_birth in ('China','Kosovo','Brazil');

SELECT * FROM person WHERE date_of_birth BETWEEN DATE '2018-04-10' AND '2019-01-01' ORDER BY date_of_birth;

Similar words - we can find emails ending in '.com'.

SELECT * FROM person WHERE email LIKE '%.com';

Or any gmail address:

SELECT * FROM person WHERE email LIKE '%@gmail.%';

Or particular characters, where three precede 'gmail.com' and it's case insensitive:

SELECT * FROM person WHERE email iLIKE '___@gmail.com';

Groups and Aggregates

Select all countries as a complete mess:

SELECT country_of_birth FROM person;

Select countries with proper grouping:

SELECT country_of_birth FROM person GROUP BY country_of_birth;

Select countries and count instances:

SELECT country_of_birth, COUNT(*) FROM person GROUP BY country_of_birth ORDER BY country_of_birth;

Also select a minimum number with 'having'. What you have must be before 'order by'.

SELECT country_of_birth, COUNT(*) FROM person GROUP BY country_of_birth HAVING COUNT(*) > 5;

SELECT country_of_birth, COUNT(*) FROM person GROUP BY country_of_birth HAVING COUNT(*) >= 10;

Other aggregates include 'max', 'min'.

Select most expensive car:

SELECT MAX(price) FROM car;

SELECT MIN(price) FROM car;

SELECT AVG(price) FROM car;

We can stick items together for better grouping:

SELECT make, model, MAX(price) FROM car GROPU BY make, model;

Select all fields from table 'car', and add a column containing another price, discounted to 90%, rounded to two decimal places.

SELECT id,make,model,price,ROUND(price * .9, 2) from car;

Same thing, but take 10% of the price from the price.

SELECT id,make,model,price,ROUND(price - (price * .1), 2) from car;

Comparison

SELECT 10 + 2^2;

SELECT 10! * 2 - 3;

... et c.

This returns false:

SELECT 1 = 1;

These return false:

SELECT 2<1;

Or '1 is not equal to 1':

SELECT 1<>1;

And with strings, 'G is not the same as g':

SELECT 'G'<>'g';

Car Disconts

You want to show the discounts on various cars. You check which columns are available and select all of them:

\d car

SELECT id,make,model,price FROM car;

Aliases

You can change what a column name appears as with:

select price AS original_price from car;

Null Values

Coalesce

You can input a series of entries, requesting the first one which is present. Here we input three entries which are 'null', and a third which is '2', so '2' is selected:

SELECT COALESCE(null, null, 2) AS number;

When selecting column 'email' from table 'person', you can input the string 'Email not provided' if there is no email provided:

SELECT COALESCE(email, 'Email not provided') from person;

Nullif

Normally, devision by 0 produces an error:

SELECT 10/ 0;

But 10 divided by 'null' produces only 'null', which is not an error.

The 'nullif' statement takes two numbers, and returns 'null' iff the numbers are the same as each other.

select nullif(0,0) select nullif(10,10)

Date

Select date:

SELECT NOW()::DATE;

SELECT NOW()::TIME;

or just:

SELECT NOW();

More here.

2h23m