PostgreSQL tips
Posted on 2018-03-07 in Trucs et astuces
Sommaire
Update fields in JSONB format
Use the jsonb_set(COLUMN_NAME, PATH_TO_CHANGE, VALUE) function. The value must be a valid value in JSON (ie use '500' for numbers, 'true' for boolean and '"str"' for strings). Examples:
-- Set the postcode field to the 92600 integer. UPDATE sales SET address = jsonb_set(address, '{postcode}', '92600') WHERE id = 47880; -- Set a nested field to the "FRA" value. Note: the nested object must exists. UPDATE sales SET address = jsonb_set(address, '{country,code}', '"FRA"'); -- Set a value at a given position in an array (an object must exist at this position). UPDATE sales SET phones = jsonb_set(phones, '{0,number}', '"06"');
CSV export/import
To export content of a table to a CSV file (eg to re-import it in a different database on a different server). Update the query and connection options to fit your needs:
psql -U user -c 'COPY (SELECT * FROM sales WHERE id = 110683) To STDOUT WITH CSV HEADER;' database > /tmp/sales.csv
To import the data from a CSV file, you need to specify the columns you want to import. To find them, run head -n 1 /tmp/sales.csv to get the first lines of the CSV which contains the headers. You can then run the command below.
psql -U user database -c "COPY sales(id,organization_id,date,name,address) FROM STDIN WITH CSV HEADER;" < /tmp/sales.csv
Note 1: it should be possible to import the data with psql -U user database -c "COPY sales(id,organization_id,date,name,address) FROM '/tmp/sales.csv' WITH CSV HEADER;". However, when I tried that, I got: ERROR: could not open file "/tmp/sale.csv" for reading: No such file or directory even though the file existed.
Note 2: you can also achieve this with pgAdmin with you want a nice GUI.
Update rows in bulks
This will update rows by batch of 100 without being blocked by locks. It is useful to prepare for the addition of an NOT NULL constraint without downtime.
UPDATE server_info SET status = 'active' WHERE server_ip = ( SELECT server_ip FROM server_info WHERE status = 'standby' LIMIT 100 FOR UPDATE SKIP LOCKED )
Understand lock issues
This will display all queries blocked by locks and which query is blocking them (pg 9.6+):
SELECT pid, usename, pg_blocking_pids(pid) AS blocked_by, state, age(now(), query_start) AS age, query AS blocked_query FROM pg_stat_activity ORDER BY age DESC NULLS LAST;
Use variables in query
Use a CTE:
WITH myconstants (var1, var2) as ( values (5, 'foo') ) SELECT * FROM somewhere, myconstants WHERE something = myconstants.var1 OR something_else = myconstants.var2;
Database sizes
To view the size of tables in a database:
SELECT nspname || '.' || relname AS "relation", pg_size_pretty(pg_total_relation_size(C.oid)) AS "total_size" FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE nspname NOT IN ('pg_catalog', 'information_schema') AND C.relkind <> 'i' AND nspname !~ '^pg_toast' ORDER BY pg_total_relation_size(C.oid) DESC LIMIT 20;
To view the sizes of databases:
SELECT pg_database.datname, pg_size_pretty(pg_database_size(pg_database.datname)) AS size FROM pg_database ORDER BY size DESC;
Source: http://www.postgresqltutorial.com/postgresql-database-indexes-table-size/