====== PostgreSQL ====== ===== Basics ===== ''\q'' exit. Know the postgresql version: ''SELECT version();'' To explore the server: * ''\list'' or ''\l'': list all databases * ''\dt'': list all tables in the current database * ''\connect database_name'' to switch database To access to a recently installed postgres server: su - postgres pgsql To add a password: ''\password'' ==== Command-line utils ==== ''psql -U postgres'' enter into console with user postgres. ''psql -U postgres -h 127.0.0.1'' for doing by TCP. ''export PGPASSWORD=mysecretpassword && psql -h 127.0.0.1 -U postgres'' using a password. $ export PGPASSWORD=mysecretpassword && dropdb -h 127.0.0.1 -U postgres fok $ export PGPASSWORD=mysecretpassword && createdb -T template0 -h 127.0.0.1 -U postgres fok ==== Create schema ==== create schema api; ==== Create table and insert ==== create table api.todos ( id serial primary key, done boolean not null default false, task text not null, due timestamptz ); insert into api.todos (task) values ('finish tutorial 0'), ('pat self on back'); ==== Make a role ==== create role web_anon nologin; grant web_anon to postgres; grant usage on schema api to web_anon; grant select on api.todos to web_anon; The web_anon role has permission to access things in the api schema, and to read rows in the todos table. ... Other: create role todo_user nologin; grant todo_user to postgres; grant usage on schema api to todo_user; grant all on api.todos to todo_user; grant usage, select on sequence api.todos_id_seq to todo_user; ==== Change user password ==== ALTER USER user_name WITH PASSWORD 'new_password'; ===== JSONB ===== You can create a table with json data: create table macarrodes.bookmarks ( id serial primary key, title text, meta jsonb ); ==== Query ==== Simple query showing a field: select distinct meta->'tags' from macarrodes.macarrodes.bookmarks; Query by field: SELECT * FROM users WHERE metadata @> '{"country": "Peru"}'; SELECT * FROM users WHERE metadata->>'country' = 'Peru'; Query nested values: SELECT * FROM users WHERE metadata->'company'->>'name' = "Mozilla"; SELECT * FROM users WHERE metadata @> '{"company":{"name": "Mozilla"}}'; Query if exists: SELECT * FROM users WHERE metadata->>'country' IS NOT NULL; Query in array: SELECT * FROM users WHERE metadata @> '{"companies": ["Mozilla"]}'; SELECT * FROM users WHERE metadata->>'countries' IN ('Chad', 'Japan'); Remove an attribute: UPDATE users SET metadata = metadata - 'country'; ===== Funciones ===== ==== Condicional CASE ==== * https://www.postgresql.org/docs/9.2/static/functions-conditional.html SELECT * FROM test; a --- 1 2 3 SELECT a, CASE WHEN a=1 THEN 'one' WHEN a=2 THEN 'two' ELSE 'other' END FROM test; a | case ---+------- 1 | one 2 | two 3 | other case when p.parent_id is null then false else true end as has_parent ==== CAST y tipos ==== Crear un tipo: CREATE TYPE temp_options_type AS (id integer, description text); Castear: CAST ( expression AS type ) expression::type ==== Objetos anidados con array y row ==== create type inner_value as (id integer, name text); create view macarrodes.bookmarks as select ... case when t_bookmarks.folder is null then null else ROW(t_bookmarks.folder, t_folders.name)::inner_value end as folder, array( select row(macarrodes.t_tags.id, macarrodes.t_tags.name)::inner_value from macarrodes.t_tags, macarrodes.t_bookmarks_tags where t_tags.id = t_bookmarks_tags.tag AND t_bookmarks.id = t_bookmarks_tags.bookmark ) as tags from macarrodes.t_bookmarks ... ''ROW(t_bookmarks.folder, t_folders.name)::inner_value'' crea un objeto ''inner_value''. Se ha de definir antes el tipo ''inner_value''. ''array(...)'' crea un array de ''inner_value''s. También podrías coger una tabla entera como tipo: select dep.*, array( select row(emp.*)::emp from emp where emp.depid = dep.depid ) emps from dep ===== Notes ===== ==== Backups and tools ==== There is a command to create a DB: createdb -T template0 restored_database To create a backup: pg_dump postgres > postgres_db.bak To restore a backup: createdb -T template0 restored_database psql restored_database < database.bak Backup and restore all DB: pg_dumpall > backup_file You can restore the databases by passing the file to psql, with the default database: psql -f backup_file postgres ==== Tips and Tricks ==== Script for restart and adding data using docker. docker stop `cat last_docker_id.txt` docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword postgres:9.4 > last_docker_id.txt sleep 6 export PGPASSWORD=mysecretpassword psql -h 127.0.0.1 -U postgres -f /home/alfred/Workspaces/macarrodes/pgsql/schema.pgsql psql -h 127.0.0.1 -U postgres -f /home/alfred/Workspaces/macarrodes/pgsql/fake_data.pgsql === Launch a command on CLI === export PGPASSWORD=mysecretpassword && psql -h 127.0.0.1 -p {db.local_port} -U postgres -c 'create database puma;' ==== Instalar servidor ==== apt-get install postgresql postgresql-contrib # Crear un cluster para 9.3 pg_createcluster 9.3 main --start # Crear servicio update-rc.d postgresql enable # Activar servicio service postgresql start # Conecta correctamente? su postgres psql \q # Ctrl+d Para permitir otras conexiones locales campiaremos local all postgres peer Por: local all postgres md5