# Postgresql Recipes
## Cài đặt
#### HĐH Ubuntu/Linux
Offical URL: https://www.postgresql.org/download/linux/ubuntu/
```
# Create the file repository configuration:
$ sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
# Import the repository signing key:
$ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
# Update the package lists:
$ sudo apt-get update
# Install the latest version of PostgreSQL.
# If you want a specific version, use 'postgresql-12' or similar instead of 'postgresql':
$ sudo apt-get -y install postgresql-12 postgresql-client-12 postgresql-contrib-12
```
#### HĐH Window / MacOS
Download version tương ứng tại https://www.enterprisedb.com/downloads/postgres-postgresql-downloads
## Đăng nhập/Đăng xuất
#### Đăng nhập - Sử dụng Ubuntu-terminal
```
$ sudo -i -u postgres
$ psql
hoặc
$ sudo -i -u postgres psql
```
#### Đăng xuất - Sử dụng Ubuntu-terminal
```
$ \q
hoặc Ctrl + D
```
## Thao tác với Databases
### Show Databases:
```
=# \l
```
### Create Database:
```
=# CREATE DATABASE db_name;
```
### Delete Database:
```
=# DROP DATABASE IF EXISTS db_name;
```
### Chọn Database để thao tác:
```
=# \c db_name;
```
### Tạo mới User, set password & gán quyền SUPERUSER cho user:
```
=# CREATE USER db_user;
=# ALTER USER db_user with encrypted password 'password';
hoặc
=# CREATE USER db_user WITH PASSWORD 'password';
```
### Show Users List:
```
=# SELECT usename FROM pg_user;
```
### Gán Users thành Superuser:
```
=# ALTER USER db_user WITH SUPERUSER;
```
*Note: bước này gán db_user thành Superuser, thường sử dụng khi user cần quyền tạo extension trên hệ thống hoặc một số tác vụ khác...*
### Delete User:
```
=# DROP USER db_user;
```
### Gán ALL PRIVILEGES cho User theo Database:
```
=# GRANT ALL PRIVILEGES ON DATABASE db_name TO db_user;
```
### Drop all database trong schema
```
=# DROP SCHEMA public CASCADE;
=# CREATE SCHEMA public;
=# GRANT ALL ON SCHEMA public TO postgres;
=# GRANT ALL ON SCHEMA public TO public;
```
## Xử lý các case đặc biệt
### Ngắt kết nối từ bên ngoài vào database
```
=# REVOKE CONNECT ON DATABASE target_db FROM public;
```
### Đổi tên database trong psql
1. Ngắt kết nối từ bên ngoài vào database
2. Execute command
```
=# ALTER DATABASE target_db RENAME TO new_name;
```
### Xử lý khi gặp "ERROR: duplicate key violates unique constraint"
Note: trường hợp này gặp khi key_sequence của table trong postgres bị trùng với dữ liệu đã có
Ví dụ:
- key_sequence sinh ra để khi insert 1 row data, key của row đó sẽ bằng key_sequence, sau đó key_sequence++
- tuy nhiên bằng cách nào đó (developer cố ý gán giá trị cho key hay import data từ excel), có 1 row trong table đã có giá trị key bằng giá trị hiện tại của key_sequence => báo lỗi **"ERROR: duplicate key violates unique constraint"**
```
=# SELECT MAX(primary_key) FROM target_table;
=# SELECT nextval('primary_key_sequence'); # check value primary_key_sequence
cuối cùng:
=# SELECT setval('primary_key_sequence', (SELECT MAX(primary_key) FROM target_table)+1);
```
eg:
```
=# SELECT setval('shop_id_seq', (SELECT MAX(id) FROM shop)+1) from shop;
```
*Hiểu đơn giản cách này set key_sequence = (max_value của primary_key) + 1*
### DROP DATABASE khi gặp "ERROR: database "sms_test" is being accessed by other users"
1. Ngắt kết nối từ bên ngoài vào database
2. Run command
```
=# SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = 'target_db';
```
### Restore file .sql
**Trỏ đến path /usr/bin/psql rồi link đến file là xong**
> Note: với trường hợp server là CentOS
cần export file với định dạng .sql rồi upload file đó lên server
> Change owner file sang postgres
> Tạo database và user, password đăng nhập giống hệt file đã export
> sudo sang root chạy câu lệnh psql là xong:
```
$ sudo chown -R postgres. /home/longdh/sp_test.sql;
$ sudo -u postgres psql sms_test < '/home/longdh/sp_test.sql';
```
### Path trỏ tới pg_dump trên MacOS
```
/Library/PostgreSQL/10/bin/pg_dump
```
### Tìm path của pg_dump trên centos 7
```
$ find / -name pg_dump -type f 2>/dev/null
```
### Restart Postgres trên MacOS
```
$ sudo su postgres -c "/Library/PostgreSQL/12/bin/pg_ctl restart -D /Library/PostgreSQL/12/data"
```
### Gặp lỗi Error: pg_config executable not found khi cài pip
Lỗi này do thiếu file pg_config ở trong máy chủ Ubuntu/Debian
```
$ sudo apt-get install libpq-dev
```
## Duplicate a Postgres database trên localhost
1. KILL ALL EXISTING CONNECTION FROM ORIGINAL DB (SOURCE_DB)
```
=# SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'SOURCE_DB' AND pid <> pg_backend_pid();
```
2. CLONE DATABASE TO NEW ONE(TARGET_DB)
```
=# CREATE DATABASE TARGET_DB WITH TEMPLATE SOURCE_DB OWNER USER_DB;
```
## Uninstall - Postgres trên Linux
1. Check list postgres đang tồn tại trên hệ thống
```
$ dpkg -l | grep postgres
```
2. Xóa bọn nó bằng lệnh purge remove
```
$ sudo apt-get --purge remove pgdg-keyring postgresql-12 postgresql-client-12 postgresql-client-common postgresql-common
```
## Postgres với Docker
Một cách sử dụng Postgresql thuận tiện hơn và không phải cài đặt phức tạp là thông qua Docker, ở đây là guide hướng dẫn start một docker container
Vấn đề:
* Cần cấu hình để có thể truy cập postgres trong docker container từ máy local (do mặc định khi khởi chạy postgres chỉ cho kết nối từ trong container)
* Cần chỉ định port để truy cập đến postgres (mapping local port với container port)
* Cần lưu lại data tại máy local để khi container khởi động lại không bị mất dữ liệu
1. Pull images
```
$ docker pull postgres
```
Check lại bằng **docker images**
2. Tạo file postgresql.conf và thêm dòng **listen_addresses = '*'**
```
$ echo "listen_addresses = '*'" > postgresql.conf
```
3. Khởi chạy container
```
$ docker run --name local-postgres -p 5434:5432 -v "$PWD/postgresql.conf":/etc/postgresql/postgresql.conf -v "$PWD/data":/var/lib/postgresql/data -e POSTGRES_PASSWORD=secret123 postgres
```
Trong đó:
* **-p 5434:5432** mapping local_port:5434 ~ container_port:5432
* **-v "$PWD/postgresql.conf":/etc/postgresql/postgresql.conf** sử dụng file postgresql.conf đã tạo ở bước 2 để làm file config của container
* **-v "$PWD/data":/var/lib/postgresql/data** mapping thư mục data ở local với thư mục data của container => data được lưu ở local
4. Check lại connect trên local với
DB_NAME = postgres
DB_USER = postgres
DB_PASSWORD = secret123
DB_HOST = localhost
DB_PORT = 5434
## Postgres với Docker-compose
Bao gồm 2 file và .docker sẽ để docker tự tạo
.
├── .docker
├── .env
├── docker-compose.yaml
└── postgresql.conf
docker-compose.yaml
```
version: "3.4"
services:
db:
image: postgres:13.1
volumes:
- $PWD/postgresql.conf:/etc/postgresql/postgresql.conf
- $PWD/.docker/db/data:/var/lib/postgresql/data
expose:
- "5432"
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
ports:
- "${DB_MAPPING_PORT}:5432"
restart: unless-stopped
```
postgresql.conf
```
listen_addresses = '*'
```
.env
```
DB_NAME = your_db
DB_USER = your_db
DB_PASSWORD = your_db
DB_MAPPING_PORT = 5432
```