-
Notifications
You must be signed in to change notification settings - Fork 1
PostgreSQL
Note:
-
pg
stands for PostgreSQL daemon - DB is accessible through URL-like adresses,
postgres://<USERNAME>:<PASSWORD>@<HOST>:<PORT>/<DB_NAME>
, eg postgres://foo:bar@localhost:5432/videotapes - pg_cli stands for PostgreSQL command-line interface (
psql
) - ALWAYS end pg_cli instructions with semicolon ;
- pg_cli connect this way
psql postgres://postgres@localhost:5432/my_database
- default port is 5432, but can be altered in
/etc/postgresql/<VERSION>/main/postgresql.conf
(ubuntu)
- check ps is running
pg_lsclusters
systemctl list-unit-files | grep enabled | grep postgres
pgrep -u postgres -fa -- -D
- stop postgresql service:
sudo service postgresql stop
- you may need to use version
sudo systemctl stop postgresql@12-main
- start server:
pg_ctl start -l logfile
or here
Steps (from there):
- install it using package manager (with aptitude:
sudo apt-get install postgresql postgresql-contrib libpq-dev
- check startup log:
tail /var/log/postgresql/postgresql-*.log
- check postgreSQL is started by opening prompt
sudo -u postgres psql
, leave by\q
- create an linux user account
sudo adduser <OS_USER_NAME>
- create a role
sudo -u postgres createuser --interactive
, supplying the newly created linux user account (<POSTGRESQL_ROLE_NAME> = <OS_USER_NAME>
)
- locate your authentication file
sudo find /etc/postgresql -name "pg_hba.conf"
sudo vi <PATH_TO_PG-HBA>/pg_hba.conf
- locate block
# Database administrative login by Unix domain socket local all postgres peer
- change
peer
tomd5
- reload pg service
sudo /etc/init.d/postgresql reload
Links:
Overview:
- create a user named
postgres
, add it to Administrator group; - open a windows as postgres user:
runas /user:postgres cmd.exe
.
- create data container :
docker create -v /var/lib/postgresql/data --name PostgreSQLData alpine
- create executable container :
docker run -p 5432:5432 --name PostgreSQL -e POSTGRES_PASSWORD=yourPassword -d --volumes-from PostgreSQLData postgres
Steps:
- create data container :
docker create -v /var/lib/postgresql/data --name PostgreSQLData alpine
- create executable container :
docker run -p 5432:5432 --name PostgreSQL -e POSTGRES_PASSWORD=yourPassword -d --volumes-from PostgreSQLData postgres
- connect to database:
docker exec -it --user postgres PostgreSQL psql
- create database:
create database sandbox;
- switch to database
\connect sandbox;
mkdir -p PATH_TO_DB_DATA_STORAGE docker run --name CONTAINER_NAME --publish LOCAL_PORT:5432 --env POSTGRES_DB=DATABASE_NAME --env POSTGRES_USER=USER_NAME --env POSTGRES_PASSWORD=USER_PASSWORD --volume PATH_TO_DB_DATA_STORAGE:/var/lib/postgresql/data --detach postgres
Load a sample database
- get backup
- extract it, whould get a .tar file
- upload backup inside container
docker cp ./dvdrental.tar PostgreSQL:/tmp
- create database dvdrental
- import backup
pg_restore -U postgres -d dvdrental /tmp/dvdrental.tar
- connect:
docker exec -it --user postgres PostgreSQL psql -d dvdrental
- list tables
\dt
- check content:
SELECT COUNT(*) FROM city;
Steps:
- get pg location
pg_config --sysconfdir
- create a global initialization file
sudo vi <PG_LOCATION>/psqlrc
- paste
\set AUTOCOMMIT off
- restart OS and check
Steps:
- open pg CLI
- type
\set AUTOCOMMIT OFF
- commit
COMMIT;
- check
\echo :AUTOCOMMIT
Get a nice command prompt (originally here)
-- Command prompt config -- on main prompt, display [local/domain] user@database \set PROMPT1 '%[%033[1m%]%M %n@%/%R%[%033[0m%]%# ' -- on a multi-line prompt, displays "more" \set PROMPT2 '[more] %R > '
-- By default, NULL displays as an empty space. -- Is it actually an empty string, or is it null? -- This makes that distinction visible displaying [NULL] instead \pset null '[NULL]' -- Use table format (with headers across the top) by default, but switch to -- expanded table format when there's a lot of data, which makes it much -- easier to read. \x auto -- Verbose error reports. \set VERBOSITY verbose -- Use a separate history file per-database. \set HISTFILE ~/.psql_history- :DBNAME -- If a command is run more than once in a row, only store it once in the -- history. \set HISTCONTROL ignoredups -- Autocomplete keywords (like SELECT) in upper-case, even if you started -- typing them in lower case. \set COMP_KEYWORD_CASE upper
Lost admin (postgres) password:
- add to pg_hba.conf :
local all all trust
- restart :
sudo service postgresql restart
- connect :
sudo -u postgresql psql
- restart :
ALTER USER postgres with password '<PASSWORD>';
- comment in pg_hba.conf :
local all all trust
- restart :
sudo service postgresql restart
- connect :
sudo -u postgresql psql
2 basic rules:
- if name is enclosed by double quotes (not simple), case is preserved: "testData" => "testData"
- if not, its case if transformed to lower-case : testData => testdata
- case is preserved;
- name is stored including double quotes, so can only be referenced using double-quotes.
CREATE TABLE "Test" (id INTEGER); INSERT INTO test VALUES (1); relation "test" does not exist CREATE TABLE "test" (id INTEGER); INSERT INTO test VALUES (1); INSERT 0 1
What can be an annoying behavior on a single word can be much worse when using more than one word.
CREATE TABLE IngredientRecipeByName (idRecipe INTEGER); INSERT INTO IngredientRecipeByName (idRecipe) VALUES (1);
Although you think everything is right, when you browse table, it appears as ingredientrecipebyname
. If you want to keep the CamelCase, you'll have to
CREATE TABLE "IngredientRecipeByName" ( "idRecipe" INTEGER ); INSERT INTO "IngredientRecipeByName" ( "idRecipe" ) VALUES ( 1 );
If you want to dispense of double-quotes entirely, to save you loads of double-quotes, but still get readable names, switch to snake_case case-insensitive pattern. Kebab-spinal-case isn't supported BTW
CREATE TABLE recipe-ingredient (recipe-id INTEGER, ingredient-id); syntax error at or near "-" CREATE TABLE recipe_ingredient (recipe_id INTEGER, ingredient_id INTEGER); INSERT INTO recipe_ingredient (recipe_id, ingredient_id) VALUES (1, 3); CREATE TABLE recipe_ingredient (recipe_id INTEGER, ingredient_id INTEGER);
Another special case: you need double-quote around column name, even when not case-sensitive in a SET See here
Basic:
- test:
TEXT
- number:
- integer:
INTEGER
- with decimal part:
NUMBER
- integer:
List:
- current user:
current_user
-
SELECT * FROM user;
, misleading if you create a table named user yourself)
- current database:
current_database()
- current user:
current_database()
Some of them are:
- SQL compliant
- specific
A naïve parsing of email
-- p_new_email = username@domain-name.com arobase_position_in_email = position('@' IN p_new_email); email_domain_length = char_length(p_new_email) - arobase_position_in_email; new_email_domain = substring( p_new_email from (arobase_position_in_email + 1) for email_domain_length); -- new_email_domain = domain-name.com
- read committed: transaction T1 will not see T2 data before T2 has commited
- repeatable read (defauklt): transaction T1 will always read the same data until T1 has commited (even if T2 has changed it it the meanwhile)
- serializable: transaction T1 cannot update data if these have been modified in the meanwhile (an error "could not serialize access" is thrown)
SET SESSION <ISOLATION_LEVEL>
Transaction starts with BEGIN
Simple transaction
\set AUTOCOMMIT off TRUNCATE TABLE recipe; COMMIT; BEGIN; INSERT INTO recipe(name, serving, source) values ('bread', 2, 'freshloaf.com'); COMMIT; INSERT INTO recipe(name, serving, source) values ('curry', 4, 'my-curry.com'); ROLLBACK; SELECT * FROM recipe; -- shows bread, but no curry
Complex transaction
\set AUTOCOMMIT off TRUNCATE TABLE recipe; COMMIT; BEGIN; INSERT INTO recipe(name, serving, source) values ('bread', 2, 'freshloaf.com'); SAVEPOINT bread; INSERT INTO recipe(name, serving, source) values ('curry', 4, 'my-curry.com'); SAVEPOINT curry; ROLLBACK TO bread; SELECT * FROM recipe; -- shows bread, but no curry
Message current transaction is aborted, commands ignored until end of transaction block
points out an error has occured and you didn't rollback. PG will not run any other query, you'll have to ROLLBACK.
- how
- logging_collector=on/off
- log_directory=PATH
- log_filename=PATTERN
- logging_collector=on/off
- where
- log_destination=stderr/csvlog
- details
- log_duration=on/off
- log_error_verbosity=TERSE/DEFAULT/VERBOSE
- what
- log_connections=on/off
- log_statement=dml/mod/all
- log_lock_waits=on/off
- log_temp_files=0
- log_replication_commands=on/off
-c logging_collector=on -c log_destination=stderr -c log_directory=/tmp -c log_duration=on -c log_error_verbosity=VERBOSE -c log_connections=on -c log_statement=all -c log_lock_waits=on -c log_temp_files=0 -c log_replication_commands=on
Verbose connection/statement/locks in file: -c logging_collector=on -c log_destination=stderr -c log_directory=/tmp -c log_duration=on -c log_error_verbosity=VERBOSE -c log_connections=on -c log_statement=all -c log_lock_waits=on
Verbose statement in file: -c logging_collector=on -c log_destination=stderr -c log_directory=/tmp -c log_duration=on -c log_error_verbosity=VERBOSE -c log_statement=all
Pass on command-line using -c SETTING
docker container run -d postgres:alpine -c logging_collector=on -c log_destination=stderr -c log_directory=/tmp -c log_statement=all
Pass on command-line using -c SETTING In docker-compose.yml
image: postgres:alpine command: postgres -c logging_collector=on -c log_destination=stderr -c log_directory=/tmp -c log_statement=all
List:
- get log name:
docker exec -it CONTAINER_ID ls /tmp/postgresql-*.log
- watch log:
docker exec -it CONTAINER_ID tail -f /tmp/postgresql-2020-06-13_142349.log
Untested:
List:
- no dependencies:
DELETE FROM TABLE foo WHERE id = 1;
- dependencies:
DELETE FROM TABLE foo WHERE id = 1 CASCADE;
List:
- no dependencies (DELETE privilege, slow, no space reclaim without VACUUM):
DELETE FROM TABLE foo;
- no dependencies (TRUNCATE privilege, ACCESS EXCLUSIVE lock):
TRUNCATE TABLE foo;
- dependencies:
TRUNCATE TABLE foo CASCADE;
List: - static, no DB / python: pgsanity