<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://entorb.net//wiki/index.php?action=history&amp;feed=atom&amp;title=PostgreSQL</id>
	<title>PostgreSQL - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://entorb.net//wiki/index.php?action=history&amp;feed=atom&amp;title=PostgreSQL"/>
	<link rel="alternate" type="text/html" href="https://entorb.net//wiki/index.php?title=PostgreSQL&amp;action=history"/>
	<updated>2026-05-06T10:28:15Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://entorb.net//wiki/index.php?title=PostgreSQL&amp;diff=5230&amp;oldid=prev</id>
		<title>Torben: /* Find and Delete Locks / Processes */</title>
		<link rel="alternate" type="text/html" href="https://entorb.net//wiki/index.php?title=PostgreSQL&amp;diff=5230&amp;oldid=prev"/>
		<updated>2025-05-21T06:56:25Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;Find and Delete Locks / Processes&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;[[Category:Coding]]&lt;br /&gt;
==Connect via single line connection string==&lt;br /&gt;
 postgresql:user:password@host:5432/database&lt;br /&gt;
&lt;br /&gt;
==SELECT==&lt;br /&gt;
===Date handling===&lt;br /&gt;
====Filter on date====&lt;br /&gt;
 SELECT * FROM table WHERE created &amp;gt; &amp;#039;2020-06-22 00:00:00+02&amp;#039;;&lt;br /&gt;
 SELECT * FROM table WHERE created &amp;gt; current_timestamp - &amp;#039;3 hours&amp;#039;::interval;&lt;br /&gt;
 SELECT * FROM table WHERE created &amp;gt; current_date - 91;  -- days&lt;br /&gt;
 SELECT * FROM table WHERE created &amp;gt; now() at time zone &amp;#039;utc&amp;#039; - interval &amp;#039;10 minute&amp;#039;;&lt;br /&gt;
 # day of week filter&lt;br /&gt;
 SELECT * FROM table WHERE EXTRACT(DOW FROM created) = 0;&lt;br /&gt;
&lt;br /&gt;
====date_trunc: convert date====&lt;br /&gt;
 SELECT date_trunc(&amp;#039;hour&amp;#039;, t.created) as hour FROM table t;&lt;br /&gt;
 SELECT date_trunc(&amp;#039;day&amp;#039;, t.created)::date AS created_date FROM  table t;&lt;br /&gt;
 SELECT date_trunc(&amp;#039;week&amp;#039;, t.created)::date AS week FROM  table t;&lt;br /&gt;
 SELECT date_trunc(&amp;#039;month&amp;#039;, t.created)::date AS month FROM  table t;&lt;br /&gt;
&lt;br /&gt;
====extract====&lt;br /&gt;
 SELECT EXTRACT (hour   from datecol) FROM myTable&lt;br /&gt;
 SELECT EXTRACT (isodow from datecol) FROM myTable -- weekno&lt;br /&gt;
 SELECT EXTRACT (dow    from datecol) FROM myTable -- weekday&lt;br /&gt;
 SELECT EXTRACT(epoch FROM closed - created) / 3600 AS hours FROM myTable -- difference in hours&lt;br /&gt;
&lt;br /&gt;
====other====&lt;br /&gt;
 # gen list of dates&lt;br /&gt;
 SELECT i::date AS day FROM generate_series(&amp;#039;2020-01-01&amp;#039;, CURRENT_DATE, &amp;#039;1 day&amp;#039;::interval) i&lt;br /&gt;
&lt;br /&gt;
====Group by date and add missing days with zero count====&lt;br /&gt;
 WITH all_days AS (&lt;br /&gt;
     SELECT generate_series(&amp;#039;01.01.2023&amp;#039;, current_date, &amp;#039;1 day&amp;#039;) :: date AS date&lt;br /&gt;
 ), count_per_day AS (&lt;br /&gt;
     SELECT&lt;br /&gt;
         created :: date AS date,&lt;br /&gt;
         COUNT(*) AS count&lt;br /&gt;
     FROM my_table&lt;br /&gt;
     GROUP BY 1&lt;br /&gt;
 )&lt;br /&gt;
 SELECT&lt;br /&gt;
     all_days.date,&lt;br /&gt;
     COALESCE (count, 0) AS count&lt;br /&gt;
 FROM all_days&lt;br /&gt;
     LEFT OUTER JOIN count_per_day ON all_days.date = count_per_day.date&lt;br /&gt;
 ORDER BY&lt;br /&gt;
     1 DESC;&lt;br /&gt;
&lt;br /&gt;
===cast types===&lt;br /&gt;
 select t.id, &amp;#039;matched filter1&amp;#039;::character varying(16) from table t&lt;br /&gt;
 &lt;br /&gt;
 -- 1. convert timerange to seconds&lt;br /&gt;
 -- 2. perform average&lt;br /&gt;
 -- 3. cast to nummeric to allow for rounding&lt;br /&gt;
 SELECT round(CAST(EXTRACT(EPOCH FROM avg (s.closure_date - s.date_of_start)) /3600 as numeric),1) AS avg_hours_total_avg from myTable s group by cloumn1&lt;br /&gt;
 &lt;br /&gt;
 -- convert date range to days&lt;br /&gt;
 SELECT EXTRACT (DAY FROM (current_date - date_due)) AS days FROM myTable&lt;br /&gt;
&lt;br /&gt;
====leading zeros for integer values====&lt;br /&gt;
 select TO_CHAR(plant_id, &amp;#039;fm0000&amp;#039;) from myTable&lt;br /&gt;
&lt;br /&gt;
===rounding of REALS===&lt;br /&gt;
 round(lower_specification_limit::numeric,6) as lower_specification_limit,&lt;br /&gt;
&lt;br /&gt;
===EXCEPT (=MINUS in Oracle)===&lt;br /&gt;
from [http://www.postgresqltutorial.com/postgresql-tutorial/postgresql-except/]&lt;br /&gt;
 SELECT column_list&lt;br /&gt;
 FROM A&lt;br /&gt;
 WHERE condition_a&lt;br /&gt;
 EXCEPT &lt;br /&gt;
 SELECT column_list&lt;br /&gt;
 FROM B&lt;br /&gt;
 WHERE condition_b;&lt;br /&gt;
&lt;br /&gt;
===RowSum / LAG===&lt;br /&gt;
 WITH daily_sum AS (&lt;br /&gt;
 SELECT created, sum(count_finished)&lt;br /&gt;
 FROM c_report_timeseries&lt;br /&gt;
 WHERE department_id &amp;gt; 0 &lt;br /&gt;
 GROUP BY 1&lt;br /&gt;
 ORDER BY 1&lt;br /&gt;
 )&lt;br /&gt;
 SELECT created, sum, sum - lag(sum) over (order by created) as increase&lt;br /&gt;
 FROM daily_sum;&lt;br /&gt;
&lt;br /&gt;
===Grouping and stats: min, max, avg, median===&lt;br /&gt;
 select d.name &amp;quot;Department&amp;quot;,&lt;br /&gt;
 count(*) ,&lt;br /&gt;
 min(i.modified-i.created),&lt;br /&gt;
 max(i.modified-i.created),&lt;br /&gt;
 avg(i.modified-i.created),&lt;br /&gt;
 PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY (i.modified-i.created) ) as median&lt;br /&gt;
 EXTRACT(EPOCH FROM PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY (i.modified-i.created)))::int AS median_seconds&lt;br /&gt;
 FROM table i&lt;br /&gt;
&lt;br /&gt;
===Substring===&lt;br /&gt;
 -- 087249731000011 -&amp;gt; 087249731-0000-11&lt;br /&gt;
 SELECT id, plant_id, material_number&lt;br /&gt;
 , substring (material_number FROM 1 for 9) || &amp;#039;-&amp;#039; || substring (material_number FROM 10 for 4) || &amp;#039;-&amp;#039; || substring (material_number FROM 14 for 2) AS &amp;quot;MatNoNew&amp;quot;&lt;br /&gt;
 FROM d_template t &lt;br /&gt;
 WHERE 1=1&lt;br /&gt;
 AND t.department_id = 50012487&lt;br /&gt;
 AND material_number NOT LIKE &amp;#039;%-%&amp;#039;&lt;br /&gt;
 AND length(material_number) = 15&lt;br /&gt;
 ;&lt;br /&gt;
&lt;br /&gt;
===sequence.nextval===&lt;br /&gt;
 SELECT nextval(&amp;#039;mysequence&amp;#039;);&lt;br /&gt;
===Pivot / longtable to shorttable===&lt;br /&gt;
 WITH data AS (&lt;br /&gt;
     SELECT&lt;br /&gt;
     date_trunc(&amp;#039;week&amp;#039;, created)::date AS &amp;quot;Date&amp;quot;,&lt;br /&gt;
     myType,&lt;br /&gt;
     count (*)&lt;br /&gt;
     FROM myTable&lt;br /&gt;
     GROUP BY 1,2&lt;br /&gt;
 )&lt;br /&gt;
 SELECT &amp;quot;Date&amp;quot;,&lt;br /&gt;
 max(&amp;quot;count&amp;quot;) FILTER (WHERE myType= &amp;#039;D&amp;#039;) AS &amp;quot;cntD&amp;quot;,&lt;br /&gt;
 max(&amp;quot;count&amp;quot;) FILTER (WHERE myType= &amp;#039;S&amp;#039;) AS &amp;quot;cntS&lt;br /&gt;
 max(&amp;quot;count&amp;quot;) FILTER (WHERE myType= &amp;#039;M&amp;#039;) AS &amp;quot;cntM&amp;quot;&lt;br /&gt;
 FROM data&lt;br /&gt;
 GROUP BY 1&lt;br /&gt;
 ORDER BY 1 ASC&lt;br /&gt;
&lt;br /&gt;
===Weighted Average===&lt;br /&gt;
 WITH my_table AS (&lt;br /&gt;
 SELECT id, property, val1, val2, val3&lt;br /&gt;
 CASE &lt;br /&gt;
   WHEN created&amp;gt;current_date - 365 THEN 3&lt;br /&gt;
   WHEN created&amp;gt;current_date - 730 THEN 2&lt;br /&gt;
   ELSE 1&lt;br /&gt;
 END AS weighting_factor&lt;br /&gt;
 )&lt;br /&gt;
 SELECT&lt;br /&gt;
 sum(val1*weighting_factor)/sum(weighting_factor) AS &amp;quot;val1w&amp;quot;,&lt;br /&gt;
 sum(val2*weighting_factor)/sum(weighting_factor) AS &amp;quot;val2w&amp;quot;,&lt;br /&gt;
 sum(val3*weighting_factor)/sum(weighting_factor) AS &amp;quot;val3w&amp;quot;&lt;br /&gt;
 FROM my_table&lt;br /&gt;
 GROUP BY property&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==INSERT==&lt;br /&gt;
===Insert or Update if conflict===&lt;br /&gt;
 INSERT INTO login_cnt (user_id)&lt;br /&gt;
 VALUES (%s)&lt;br /&gt;
 ON CONFLICT (user_id, &amp;quot;date&amp;quot;)&lt;br /&gt;
 DO UPDATE SET count = login_cnt.count + 1;&lt;br /&gt;
 &lt;br /&gt;
 -- login counter table&lt;br /&gt;
 CREATE TABLE&lt;br /&gt;
   login_cnt (&lt;br /&gt;
     user_id int2 NOT NULL,&lt;br /&gt;
     &amp;quot;date&amp;quot; date DEFAULT current_date NOT NULL,&lt;br /&gt;
     count int2 DEFAULT 1 NOT NULL,&lt;br /&gt;
     CONSTRAINT pkey_login_cnt PRIMARY KEY (user_id, date)&lt;br /&gt;
   );&lt;br /&gt;
&lt;br /&gt;
===Insert with conflicting IDs===&lt;br /&gt;
 insert into machine_group(id, area, number)&lt;br /&gt;
 values (6, 6, 6),&lt;br /&gt;
        (7, 6, 7),&lt;br /&gt;
        (8, 6, 8),&lt;br /&gt;
        (9, 6, 9),&lt;br /&gt;
        (10, 6, 10)&lt;br /&gt;
 on conflict (id) do nothing;&lt;br /&gt;
&lt;br /&gt;
==UPDATE==&lt;br /&gt;
===REGEXP and REGEXP_REPLACE===&lt;br /&gt;
 -- replace &lt;br /&gt;
 UPDATE mytable&lt;br /&gt;
 SET remark = REPLACE(remark, &amp;#039;&amp;amp;amp;&amp;#039;, &amp;#039;&amp;amp;&amp;#039;)&lt;br /&gt;
 WHERE remark LIKE &amp;#039;%&amp;amp;amp;%&amp;#039;&lt;br /&gt;
 &lt;br /&gt;
 -- remove _|_ -&amp;gt; linebreak \n=10&lt;br /&gt;
 UPDATE mytable&lt;br /&gt;
 SET remark = REPLACE(remark, &amp;#039;_|_&amp;#039;, chr(10) )&lt;br /&gt;
 WHERE remark LIKE &amp;#039;%_|_%&amp;#039;&lt;br /&gt;
&lt;br /&gt;
===UPDATE via SELECT===&lt;br /&gt;
update single column from another table&lt;br /&gt;
 UPDATE q_user&lt;br /&gt;
 SET    card_no = q_upload_user.card_no&lt;br /&gt;
 FROM   q_upload_user  &lt;br /&gt;
 WHERE  q_user.id = q_upload_user.id&lt;br /&gt;
&lt;br /&gt;
using WITH temp table&lt;br /&gt;
 WITH map_name_id AS &lt;br /&gt;
 (&lt;br /&gt;
 SELECT short_name, min(id) min_id&lt;br /&gt;
  FROM   q_upload_organization&lt;br /&gt;
  GROUP BY short_name &lt;br /&gt;
 )&lt;br /&gt;
 UPDATE q_upload_user2&lt;br /&gt;
 SET    department_id = map_name_id.min_id&lt;br /&gt;
 FROM   map_name_id  &lt;br /&gt;
 WHERE  q_upload_user2.dpt_short_name_sap = map_name_id.short_name&lt;br /&gt;
&lt;br /&gt;
sync table tab1 from tab2&lt;br /&gt;
 UPDATE tab1&lt;br /&gt;
 SET (group_id, error_de, error_en, error_hu) = (&lt;br /&gt;
  SELECT group_id, error_de, error_en, error_hu FROM tab2 WHERE tab1.code = tab2.code&lt;br /&gt;
 )&lt;br /&gt;
&lt;br /&gt;
===pseudonymization===&lt;br /&gt;
 UPDATE user&lt;br /&gt;
 SET&lt;br /&gt;
 username = replace( format(&amp;#039;u%7s&amp;#039;, id), &amp;#039; &amp;#039;, &amp;#039;0&amp;#039;) -- u0000001 for id=1&lt;br /&gt;
 ,first_name = (array[&amp;#039;Max&amp;#039;, &amp;#039;Egon&amp;#039;, &amp;#039;Lisa&amp;#039;]) [floor(random() * 3 + 1)]&lt;br /&gt;
 ,last_name = (array[&amp;#039;Meier&amp;#039;, &amp;#039;Müller&amp;#039;, &amp;#039;Schmidt&amp;#039;)[floor(random() * 3 + 1)]&lt;br /&gt;
 ,email = &amp;#039;no-mail@schaeffler.com&amp;#039;&lt;br /&gt;
 WHERE id = 1;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==DELETE==&lt;br /&gt;
===Performance for DELETE Statement===&lt;br /&gt;
from [https://dba.stackexchange.com/a/35007]&lt;br /&gt;
 Good: DELETE FROM foo WHERE id IN (select id from rows_to_delete);&lt;br /&gt;
 Bad:  DELETE FROM foo WHERE id NOT IN (select id from rows_to_keep);&lt;br /&gt;
 Good Alternative for the bad rows_to_keep path:&lt;br /&gt;
 DELETE FROM foo &lt;br /&gt;
  WHERE id IN (&lt;br /&gt;
   SELECT f.id FROM foo f &lt;br /&gt;
   LEFT JOIN rows_to_keep k ON f.id = k.id&lt;br /&gt;
              WHERE k.id IS NULL&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
delete based on multiple criteria also in another table&lt;br /&gt;
 DELETE FROM&lt;br /&gt;
   table1 t1&lt;br /&gt;
 WHERE&lt;br /&gt;
   EXISTS (&lt;br /&gt;
   SELECT&lt;br /&gt;
     1&lt;br /&gt;
   FROM&lt;br /&gt;
     table2 t2&lt;br /&gt;
   WHERE&lt;br /&gt;
     1 = 1&lt;br /&gt;
     AND t2.date &amp;lt; CURRENT_DATE - 30&lt;br /&gt;
     AND t1.col1 = t2.col1&lt;br /&gt;
     AND t1.col2 = t2.col2 )&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==CREATE TABLE==&lt;br /&gt;
===Create Table with auto-increment id===&lt;br /&gt;
 CREATE TABLE test_auto_id (&lt;br /&gt;
 id serial PRIMARY KEY,&lt;br /&gt;
 value TEXT NOT NULL&lt;br /&gt;
 );&lt;br /&gt;
 &lt;br /&gt;
 INSERT INTO test_auto_id (value) VALUES (&amp;#039;asdf&amp;#039;);&lt;br /&gt;
 &lt;br /&gt;
 SELECT * FROM test_auto_id ;&lt;br /&gt;
&lt;br /&gt;
===Create Table Like===&lt;br /&gt;
 -- without contents&lt;br /&gt;
 CREATE TABLE myNewTable AS SELECT * FROM myTable WHERE 1=2;&lt;br /&gt;
 -- without contents but including index etc (but no permissions)&lt;br /&gt;
 CREATE TABLE myNewTable (like myTable including all);&lt;br /&gt;
&lt;br /&gt;
===Create unlogged cache/caching table===&lt;br /&gt;
inspired from [https://martinheinz.dev/blog/105 You Don&amp;#039;t Need a Dedicated Cache Service - PostgreSQL as a Cache]&lt;br /&gt;
 CREATE UNLOGGED TABLE my_cache (&lt;br /&gt;
 url text UNIQUE NOT NULL,&lt;br /&gt;
 value jsonb,&lt;br /&gt;
 delete_at timestamp WITHOUT TIME ZONE DEFAULT now() + &amp;#039;24 hours&amp;#039;::interval );&lt;br /&gt;
 &lt;br /&gt;
 CREATE INDEX idx_cache_key ON my_cache (url);&lt;br /&gt;
 &lt;br /&gt;
 INSERT INTO my_cache  (url, value)&lt;br /&gt;
 VALUES (&amp;#039;myURL2.com&amp;#039;, &amp;#039;{&amp;quot;key&amp;quot;:&amp;quot;value&amp;quot;}&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
==FUNCTION in plpgsql==&lt;br /&gt;
 CREATE OR REPLACE FUNCTION drm.tmp_change_plant_id(id_old int, id_new int)&lt;br /&gt;
  RETURNS void AS $$   &lt;br /&gt;
 BEGIN&lt;br /&gt;
 &lt;br /&gt;
 UPDATE myTable SET col = 123 WHERE col = 456;&lt;br /&gt;
 &lt;br /&gt;
 END;&lt;br /&gt;
 $$ LANGUAGE plpgsql;&lt;br /&gt;
 ;&lt;br /&gt;
&lt;br /&gt;
==Users==&lt;br /&gt;
===grant permission to user===&lt;br /&gt;
 -- as user myuser&lt;br /&gt;
 GRANT USAGE ON SCHEMA myschema TO myuser2;&lt;br /&gt;
 GRANT SELECT, INSERT ON TABLE mytable TO myuser2;&lt;br /&gt;
&lt;br /&gt;
===read only user===&lt;br /&gt;
 CREATE USER myUser PASSWORD &amp;#039;myPassword&amp;#039;;&lt;br /&gt;
 GRANT USAGE ON SCHEMA mySchema TO myUser&lt;br /&gt;
 GRANT SELECT ON ALL TABLES IN SCHEMA mySchema TO myUser&lt;br /&gt;
 &lt;br /&gt;
 -- needed for views that are added later&lt;br /&gt;
 ALTER DEFAULT PRIVILEGES IN SCHEMA mySchema GRANT SELECT ON TABLES TO myUser;&lt;br /&gt;
 &lt;br /&gt;
 -- default to search in another schema&lt;br /&gt;
 ALTER ROLE myUser SET search_path TO mySchema, public;&lt;br /&gt;
 &lt;br /&gt;
 -- set default for transactions to read-only&lt;br /&gt;
 ALTER USER myUser SET default_transaction_read_only = on;&lt;br /&gt;
 &lt;br /&gt;
 -- check via&lt;br /&gt;
 SELECT * FROM pg_db_role_setting&lt;br /&gt;
 -- -&amp;gt; unfold the results&lt;br /&gt;
&lt;br /&gt;
===Disable user===&lt;br /&gt;
 ALTER USER myuser WITH NOLOGIN&lt;br /&gt;
&lt;br /&gt;
===Change password===&lt;br /&gt;
 ALTER USER user_name WITH PASSWORD &amp;#039;new_password&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Schema Ownership==&lt;br /&gt;
 GRANT myuser TO postgresadmin;&lt;br /&gt;
 ALTER SCHEMA myschema OWNER TO myuser;&lt;br /&gt;
 GRANT ALL ON SCHEMA myschema TO myuser;&lt;br /&gt;
 REVOKE myuser FROM postgresadmin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Other==&lt;br /&gt;
&lt;br /&gt;
===sprintf-alternative===&lt;br /&gt;
goal&lt;br /&gt;
 sprintf &amp;#039;u%07d&amp;#039;, 1&lt;br /&gt;
achieved via&lt;br /&gt;
 SELECT replace( format(&amp;#039;u%7s&amp;#039;, 1), &amp;#039; &amp;#039;, &amp;#039;0&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
===random item of list===&lt;br /&gt;
 SELECT (array[&amp;#039;Yes&amp;#039;, &amp;#039;No&amp;#039;, &amp;#039;Maybe&amp;#039;])[floor(random() * 3 + 1)];&lt;br /&gt;
&lt;br /&gt;
===Count the occurrences of a substring in a string===&lt;br /&gt;
solution based on [https://dba.stackexchange.com/questions/166762/how-do-you-count-the-occurrences-of-an-anchored-string-using-postgresql/166763#166763] and [https://stackoverflow.com/a/42708237]&lt;br /&gt;
&lt;br /&gt;
 SELECT&lt;br /&gt;
  (length(str) - length(replace(str, replacestr, &amp;#039;&amp;#039;)) )::int&lt;br /&gt;
  / length(replacestr)&lt;br /&gt;
 FROM ( VALUES&lt;br /&gt;
  (&amp;#039;foobarbaz&amp;#039;, &amp;#039;ba&amp;#039;)&lt;br /&gt;
 ) AS t(str, replacestr);&lt;br /&gt;
becomes &lt;br /&gt;
 SELECT&lt;br /&gt;
   sub1.id, &lt;br /&gt;
   (length(sub1.str) - length(replace(sub1.str, sub1.replacestr, &amp;#039;&amp;#039;)) )::int  / length(sub1.replacestr) AS times&lt;br /&gt;
 FROM&lt;br /&gt;
 (&lt;br /&gt;
 SELECT id, checklist AS str, &amp;#039;{&amp;quot;id&amp;quot;:&amp;#039;::text AS replacestr FROM d_department&lt;br /&gt;
 ) sub1&lt;br /&gt;
which counts the number of (json) ids &amp;#039;{&amp;quot;id&amp;quot;:&amp;#039; in a textfield&lt;br /&gt;
&lt;br /&gt;
===Get table column type / describe alternative===&lt;br /&gt;
 SELECT&lt;br /&gt;
   table_name,&lt;br /&gt;
   column_name,&lt;br /&gt;
   data_type,&lt;br /&gt;
   character_maximum_length&lt;br /&gt;
 FROM&lt;br /&gt;
   INFORMATION_SCHEMA.COLUMNS&lt;br /&gt;
 WHERE&lt;br /&gt;
   1 = 1&lt;br /&gt;
   AND table_schema IN (&amp;#039;schema1&amp;#039;,&amp;#039;schema2&amp;#039;)&lt;br /&gt;
   AND (table_name LIKE &amp;#039;c\_%&amp;#039; OR table_name LIKE &amp;#039;d\_%&amp;#039;)&lt;br /&gt;
   AND column_name = &amp;#039;order&amp;#039;&lt;br /&gt;
 ORDER BY&lt;br /&gt;
   table_name,&lt;br /&gt;
   column_name&lt;br /&gt;
&lt;br /&gt;
===Concatenate / string_agg columns of multiple rows===&lt;br /&gt;
 SELECT id, STRING_AGG(c.comment, &amp;#039;&lt;br /&gt;
 -----&lt;br /&gt;
 &amp;#039; ORDER BY c.created ASC) AS comment&lt;br /&gt;
 FROM comment c&lt;br /&gt;
 GROUP BY id&lt;br /&gt;
&lt;br /&gt;
==Performance Tuning==&lt;br /&gt;
use this to check the SQL speed:&lt;br /&gt;
 EXPLAIN (analyze,buffers,timing) &lt;br /&gt;
 SELECT * FROM table WHERE ...&lt;br /&gt;
&lt;br /&gt;
===EXISTS===&lt;br /&gt;
 SELECT 1 WHERE EXISTS ( SELECT 1 FROM table WHERE field = :field )&lt;br /&gt;
 --Is much faster than performing a COUNT(*) and later check if greater than 0&lt;br /&gt;
&lt;br /&gt;
===UNION vs UNION ALL===&lt;br /&gt;
UNION does include a DISTINCT, while UNION ALL does not, so if you know the data is unique, use UNION ALL&lt;br /&gt;
&lt;br /&gt;
===SELECT WHERE IN () Statement===&lt;br /&gt;
when passing a long list of values into a statement like&lt;br /&gt;
 SELECT * FROM myTable where id in (1,2,3,4,5,6,7,8,...);&lt;br /&gt;
the statement becomes very slow, see [https://stackoverflow.com/questions/39246746/postgres-query-with-in-is-very-slow]&lt;br /&gt;
&lt;br /&gt;
Better use a WITH clause (=CTE = common table expressions):&lt;br /&gt;
 WITH value_list AS (&lt;br /&gt;
   VALUES (1),(2),...&lt;br /&gt;
 )&lt;br /&gt;
 SELECT * FROM myTable WHERE id IN (SELECT * FROM value_list);&lt;br /&gt;
&lt;br /&gt;
===Find Missing Index/Indices===&lt;br /&gt;
Read https://use-the-index-luke.com/&lt;br /&gt;
&lt;br /&gt;
from https://www.cybertec-postgresql.com/en/index-your-foreign-key/&lt;br /&gt;
 SELECT c.conrelid::regclass AS &amp;quot;table&amp;quot;,&lt;br /&gt;
        /* list of key column names in order */&lt;br /&gt;
        string_agg(a.attname, &amp;#039;,&amp;#039; ORDER BY x.n) AS columns,&lt;br /&gt;
        pg_catalog.pg_size_pretty(&lt;br /&gt;
           pg_catalog.pg_relation_size(c.conrelid)&lt;br /&gt;
        ) AS size,&lt;br /&gt;
        c.conname AS constraint,&lt;br /&gt;
        c.confrelid::regclass AS referenced_table&lt;br /&gt;
 FROM pg_catalog.pg_constraint c&lt;br /&gt;
    /* enumerated key column numbers per foreign key */&lt;br /&gt;
    CROSS JOIN LATERAL&lt;br /&gt;
       unnest(c.conkey) WITH ORDINALITY AS x(attnum, n)&lt;br /&gt;
    /* name for each key column */&lt;br /&gt;
    JOIN pg_catalog.pg_attribute a&lt;br /&gt;
       ON a.attnum = x.attnum&lt;br /&gt;
          AND a.attrelid = c.conrelid&lt;br /&gt;
 WHERE NOT EXISTS&lt;br /&gt;
         /* is there a matching index for the constraint? */&lt;br /&gt;
         (SELECT 1 FROM pg_catalog.pg_index i&lt;br /&gt;
          WHERE i.indrelid = c.conrelid&lt;br /&gt;
            /* it must not be a partial index */&lt;br /&gt;
            AND i.indpred IS NULL&lt;br /&gt;
            /* the first index columns must be the same as the&lt;br /&gt;
               key columns, but order doesn&amp;#039;t matter */&lt;br /&gt;
            AND (i.indkey::smallint[])[0:cardinality(c.conkey)-1]&lt;br /&gt;
                OPERATOR(pg_catalog.@&amp;gt;) c.conkey)&lt;br /&gt;
   AND c.contype = &amp;#039;f&amp;#039;&lt;br /&gt;
 GROUP BY c.conrelid, c.conname, c.confrelid&lt;br /&gt;
 ORDER BY pg_catalog.pg_relation_size(c.conrelid) DESC;&lt;br /&gt;
&lt;br /&gt;
==Admin==&lt;br /&gt;
 SELECT version();&lt;br /&gt;
&lt;br /&gt;
===PostgreSQL Monitoring Cheatsheet===&lt;br /&gt;
see [https://russ.garrett.co.uk/2015/10/02/postgres-monitoring-cheatsheet/]&lt;br /&gt;
&lt;br /&gt;
===Disconnect all sessions===&lt;br /&gt;
 SELECT	pg_terminate_backend(pg_stat_activity.pid)&lt;br /&gt;
 FROM pg_stat_activity&lt;br /&gt;
 WHERE pg_stat_activity.datname = &amp;#039;myDB&amp;#039;&lt;br /&gt;
   AND pid &amp;lt;&amp;gt; pg_backend_pid();&lt;br /&gt;
&lt;br /&gt;
===Drop and recreate DB via psql ===&lt;br /&gt;
 SET PGPASSWORD=myPassword&lt;br /&gt;
 psql --port=5432 --username=myUser&lt;br /&gt;
 DROP database IF EXISTS myDB;&lt;br /&gt;
 CREATE database myDB;&lt;br /&gt;
 \c myDB;&lt;br /&gt;
 DROP SCHEMA IF EXISTS public;&lt;br /&gt;
 CREATE SCHEMA public;&lt;br /&gt;
 \q&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Table size including Indices===&lt;br /&gt;
 SELECT&lt;br /&gt;
     table_name,&lt;br /&gt;
     pg_size_pretty(table_size) AS table_size,&lt;br /&gt;
     pg_size_pretty(indexes_size) AS indexes_size,&lt;br /&gt;
     pg_size_pretty(total_size) AS total_size&lt;br /&gt;
 FROM (&lt;br /&gt;
     SELECT&lt;br /&gt;
         table_name,&lt;br /&gt;
         pg_table_size(table_name) AS table_size,&lt;br /&gt;
         pg_indexes_size(table_name) AS indexes_size,&lt;br /&gt;
         pg_total_relation_size(table_name) AS total_size&lt;br /&gt;
     FROM (&lt;br /&gt;
         SELECT (&amp;#039;&amp;quot;&amp;#039; || table_schema || &amp;#039;&amp;quot;.&amp;quot;&amp;#039; || table_name || &amp;#039;&amp;quot;&amp;#039;) AS table_name&lt;br /&gt;
         FROM information_schema.tables&lt;br /&gt;
     ) AS all_tables&lt;br /&gt;
     ORDER BY total_size DESC&lt;br /&gt;
 ) AS pretty_sizes;&lt;br /&gt;
&lt;br /&gt;
===Find table column candidates for type enum (less than 10 different values)===&lt;br /&gt;
 DO $$&lt;br /&gt;
 DECLARE&lt;br /&gt;
 r RECORD;&lt;br /&gt;
 query TEXT;&lt;br /&gt;
 all_queries TEXT := &amp;#039;&amp;#039;;&lt;br /&gt;
 my_table_name TEXT := &amp;#039;d_template&amp;#039;;&lt;br /&gt;
 BEGIN&lt;br /&gt;
   FOR r IN &lt;br /&gt;
   SELECT column_name, data_type&lt;br /&gt;
 FROM information_schema.COLUMNS&lt;br /&gt;
 WHERE table_name = my_table_name&lt;br /&gt;
 AND data_type NOT IN (&amp;#039;bigint&amp;#039;, &amp;#039;integer&amp;#039;, &amp;#039;timestamp without time zone&amp;#039;, &amp;#039;boolean&amp;#039;, &amp;#039;USER-DEFINED&amp;#039;)&lt;br /&gt;
 ORDER BY column_name&lt;br /&gt;
 LOOP&lt;br /&gt;
   query := &amp;#039;SELECT &amp;#039;&amp;#039;&amp;#039; || r.column_name || &amp;#039;&amp;#039;&amp;#039; AS column_name, count(*) FROM (SELECT DISTINCT &amp;#039; || r.column_name || &amp;#039; FROM &amp;#039; || my_table_name || &amp;#039; LIMIT 10) s1 HAVING count(*)&amp;lt;10&amp;#039;;&lt;br /&gt;
 --RAISE NOTICE &amp;#039;%&amp;#039;, query;&lt;br /&gt;
 IF all_queries &amp;lt;&amp;gt; &amp;#039;&amp;#039; THEN&lt;br /&gt;
 all_queries := all_queries || &amp;#039; UNION ALL &amp;#039;;&lt;br /&gt;
 END IF;&lt;br /&gt;
 all_queries := all_queries || query;&lt;br /&gt;
 END LOOP;&lt;br /&gt;
 RAISE NOTICE &amp;#039;%&amp;#039;, all_queries;&lt;br /&gt;
 --EXECUTE all_queries;&lt;br /&gt;
 END $$;&lt;br /&gt;
&lt;br /&gt;
===Vacuum / Autovacuum===&lt;br /&gt;
====Manual====&lt;br /&gt;
 VACUUM VERBOSE ANALYZE myTable;&lt;br /&gt;
or with exclusive lock:&lt;br /&gt;
 VACUUM FULL VERBOSE ANALYZE myTable;&lt;br /&gt;
====AutoVacuum====&lt;br /&gt;
 SELECT name, setting FROM pg_settings WHERE name=&amp;#039;autovacuum&amp;#039;;&lt;br /&gt;
 -- should be on&lt;br /&gt;
 SELECT * from pg_settings where category like &amp;#039;Autovacuum&amp;#039;;&lt;br /&gt;
 --overview by &lt;br /&gt;
 SELECT schemaname, relname, last_autoanalyze, last_analyze, last_autovacuum, last_vacuum, n_live_tup, n_dead_tup,*&lt;br /&gt;
 FROM &amp;quot;pg_catalog&amp;quot;.&amp;quot;pg_stat_all_tables&amp;quot;&lt;br /&gt;
 WHERE schemaname = &amp;#039;mySchema&amp;#039; &lt;br /&gt;
 ORDER BY last_autoanalyze DESC&lt;br /&gt;
&lt;br /&gt;
==Performance Analysis==&lt;br /&gt;
&lt;br /&gt;
====List of currently running Queries====&lt;br /&gt;
 SELECT pid, datname, usename, state, query, query_start, now()-query_start AS runtime, client_addr, application_name, *&lt;br /&gt;
 FROM pg_stat_activity&lt;br /&gt;
 WHERE 1=1&lt;br /&gt;
 ORDER BY query_start ASC ;&lt;br /&gt;
&lt;br /&gt;
====pg_stat_statements module====&lt;br /&gt;
pg_stat_statements module is very nice, as it displays which queries run how often and how long, see for example [https://dba.stackexchange.com/questions/44084/troubleshooting-high-cpu-usage-from-postgres-and-postmaster-services] &lt;br /&gt;
&amp;lt;br/&amp;gt;Installation &lt;br /&gt;
* postgresql.conf&lt;br /&gt;
 in : section # - Kernel Resource Usage -&lt;br /&gt;
 add: shared_preload_libraries = &amp;#039;pg_stat_statements&amp;#039;&lt;br /&gt;
* server parameter &amp;#039;pg_stat_statements.track&amp;#039; must be set to &amp;#039;top&amp;#039; or &amp;#039;all&amp;#039;&lt;br /&gt;
* restart PostgreSQL&lt;br /&gt;
 CREATE EXTENSION pg_stat_statements&lt;br /&gt;
 (in each DB)&lt;br /&gt;
* check in available extensions via&lt;br /&gt;
 SELECT * FROM pg_available_extensions WHERE name = &amp;#039;pg_stat_statements&amp;#039;&lt;br /&gt;
finally run (recent postgres version)&lt;br /&gt;
 SELECT &lt;br /&gt;
   round((total_exec_time / 1000 / 3600)::numeric,2) as total_hours,&lt;br /&gt;
   round((total_exec_time / 1000 / calls)::numeric,3) as avg_sec,&lt;br /&gt;
   calls num_calls,&lt;br /&gt;
   query&lt;br /&gt;
 FROM pg_stat_statements &lt;br /&gt;
 WHERE 1=1&lt;br /&gt;
 AND query != &amp;#039;&amp;lt;insufficient privilege&amp;gt;&amp;#039; -- only by current user&lt;br /&gt;
 -- AND lower(query) LIKE &amp;#039;%select *%join%&amp;#039;&lt;br /&gt;
 ORDER BY 2 DESC LIMIT 100;&lt;br /&gt;
finally run (old postgres version)&lt;br /&gt;
 SELECT &lt;br /&gt;
   round((total_time / 1000 / 3600)::numeric,2) as total_hours,&lt;br /&gt;
   round((total_time / 1000 / calls)::numeric,3) as avg_sec,&lt;br /&gt;
   calls num_calls,&lt;br /&gt;
   query&lt;br /&gt;
 FROM pg_stat_statements &lt;br /&gt;
 WHERE 1=1&lt;br /&gt;
 AND query != &amp;#039;&amp;lt;insufficient privilege&amp;gt;&amp;#039; -- only by current user&lt;br /&gt;
 -- AND lower(query) LIKE &amp;#039;%select *%join%&amp;#039;&lt;br /&gt;
 ORDER BY 2 DESC LIMIT 100;&lt;br /&gt;
* Grant access to non-admin users:&lt;br /&gt;
 GRANT USAGE ON SCHEMA public TO myUser;&lt;br /&gt;
 GRANT SELECT ON pg_stat_statements TO myUser;&lt;br /&gt;
* Reset stats (as admin user)&lt;br /&gt;
 SELECT pg_stat_statements_reset()&lt;br /&gt;
&lt;br /&gt;
====Check/analyze why a certain statement runs slow====&lt;br /&gt;
from [https://dba.stackexchange.com/a/226481]&lt;br /&gt;
 EXPLAIN (analyze,buffers,timing) &lt;br /&gt;
  DELETE FROM myTable WHERE id IN (&lt;br /&gt;
   SELECT id FROM myTableToDelete&lt;br /&gt;
 ) AND id &amp;gt; 2150 &lt;br /&gt;
   AND id &amp;lt; 2200 ;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 EXPLAIN ANALYZE&lt;br /&gt;
 SELECT id FROM myTableToDelete&lt;br /&gt;
&lt;br /&gt;
analyze via &lt;br /&gt;
 psql -qAt -f explain.sql &amp;gt; analyze.json&lt;br /&gt;
 http://tatiyants.com/pev/#/plans/new&lt;br /&gt;
&lt;br /&gt;
====Find and Delete Locks / Processes====&lt;br /&gt;
 GRANT pg_signal_backend TO postgresadmin WITH ADMIN OPTION;&lt;br /&gt;
 SELECT pg_terminate_backend(pid)&lt;br /&gt;
     FROM pg_stat_activity&lt;br /&gt;
     WHERE pid &amp;lt;&amp;gt; pg_backend_pid();&lt;br /&gt;
 &lt;br /&gt;
 -- Display PIDs and Queries running on a table, from [https://jaketrent.com/post/find-kill-locks-postgres/]&lt;br /&gt;
 SELECT pid, state, usename, query, query_start &lt;br /&gt;
   FROM pg_stat_activity &lt;br /&gt;
  WHERE pid IN (&lt;br /&gt;
   SELECT pid FROM pg_locks l &lt;br /&gt;
     JOIN pg_class t ON l.relation = t.oid AND t.relkind = &amp;#039;r&amp;#039; &lt;br /&gt;
    WHERE t.relname = &amp;#039;myTable&amp;#039;&lt;br /&gt;
  );&lt;br /&gt;
 &lt;br /&gt;
 -- show all processes on current DB&lt;br /&gt;
 SELECT datname, pid, state, query, age(clock_timestamp(), query_start) AS age &lt;br /&gt;
 FROM pg_stat_activity&lt;br /&gt;
 WHERE 1=1 &lt;br /&gt;
     AND state &amp;lt;&amp;gt; &amp;#039;idle&amp;#039; &lt;br /&gt;
     AND query NOT LIKE &amp;#039;% FROM pg_stat_activity %&amp;#039; &lt;br /&gt;
     AND datname = current_database() &lt;br /&gt;
 ORDER BY age;&lt;br /&gt;
 &lt;br /&gt;
 -- show locks&lt;br /&gt;
 SELECT t.relname, *&lt;br /&gt;
   FROM pg_locks l&lt;br /&gt;
   JOIN pg_class t ON l.relation = t.oid AND t.relkind = &amp;#039;r&amp;#039;&lt;br /&gt;
  WHERE t.relname != &amp;#039;pg_class&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 -- cancel process&lt;br /&gt;
 SELECT pg_cancel_backend(&amp;lt;my_pid&amp;gt;);&lt;br /&gt;
 COMMIT;&lt;br /&gt;
 &lt;br /&gt;
 -- force cancel process&lt;br /&gt;
 SELECT pg_terminate_backend(&amp;lt;my_pid&amp;gt;);&lt;br /&gt;
 COMMIT;&lt;br /&gt;
 &lt;br /&gt;
 -- force cancel all processes&lt;br /&gt;
 SELECT pg_terminate_backend(pid)&lt;br /&gt;
 FROM pg_stat_activity&lt;br /&gt;
 WHERE pid &amp;lt;&amp;gt; pg_backend_pid() AND datname = current_database();&lt;br /&gt;
 COMMIT;&lt;br /&gt;
&lt;br /&gt;
===Backup and Restore===&lt;br /&gt;
Backup&lt;br /&gt;
 SET PGPASSWORD=myPassword&lt;br /&gt;
 pg_dump.exe --host=localhost --port=5432 --username=myUser --dbname=myDB --schema=mySchema --Format c --blobs --verbose --file myDB.dmp &lt;br /&gt;
Restore (as admin user postgres)&lt;br /&gt;
 ALTER SCHEMA &amp;quot;myDB&amp;quot; RENAME TO &amp;quot;myDB.old&amp;quot;;&lt;br /&gt;
 SET PGPASSWORD=myPassword&lt;br /&gt;
 pg_restore --host=localhost --port=5432 --username=postgres --create --dbname myDB --verbose --exit-on-error myDB.dmp&lt;br /&gt;
 DROP SCHEMA &amp;quot;myDB.old&amp;quot; CASCADE;&lt;br /&gt;
&lt;br /&gt;
====Export and import single table====&lt;br /&gt;
 SET PGPASSWORD=myPassword&lt;br /&gt;
 &lt;br /&gt;
 # export single report table&lt;br /&gt;
 # use of pg_dump / restore is problematic, since it requires to have the same schema at the target DB, hence using COPY instead&lt;br /&gt;
 psql.exe --host=myHost1 --port=5432 --username=myUser --dbname=myDB --schema=mySchema ^&lt;br /&gt;
 --command=&amp;quot;COPY myTable TO STDOUT DELIMITER &amp;#039;|&amp;#039; CSV HEADER;&amp;quot; &amp;gt; myTable.csv&lt;br /&gt;
 # or&lt;br /&gt;
 psql.exe --host=myHost1 --port=5432 --username=myUser --dbname=myDB --schema=mySchema ^&lt;br /&gt;
 --command=&amp;quot;COPY (SELECT id,name FROM myTable) TO STDOUT DELIMITER &amp;#039;|&amp;#039; CSV HEADER;&amp;quot; &amp;gt; myTable.csv&lt;br /&gt;
 &lt;br /&gt;
 # import using COPY&lt;br /&gt;
 psql.exe &lt;br /&gt;
 --host=myHost1 --port=5432 --username=myUser --dbname=myDB ^&lt;br /&gt;
 -v ON_ERROR_STOP=1&lt;br /&gt;
 --command=&amp;quot;TRUNCATE TABLE myTable; COPY myTable FROM STDIN DELIMITER &amp;#039;|&amp;#039; CSV HEADER;&amp;quot; &amp;lt; myTable.csv&lt;/div&gt;</summary>
		<author><name>Torben</name></author>
	</entry>
</feed>