<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="cs">
	<id>http://postgres.cz/index.php?action=history&amp;feed=atom&amp;title=PostgreSQL_SQL_Tricks_II</id>
	<title>PostgreSQL SQL Tricks II - Historie editací</title>
	<link rel="self" type="application/atom+xml" href="http://postgres.cz/index.php?action=history&amp;feed=atom&amp;title=PostgreSQL_SQL_Tricks_II"/>
	<link rel="alternate" type="text/html" href="http://postgres.cz/index.php?title=PostgreSQL_SQL_Tricks_II&amp;action=history"/>
	<updated>2026-05-12T22:40:32Z</updated>
	<subtitle>Historie editací této stránky</subtitle>
	<generator>MediaWiki 1.43.3</generator>
	<entry>
		<id>http://postgres.cz/index.php?title=PostgreSQL_SQL_Tricks_II&amp;diff=1389&amp;oldid=prev</id>
		<title>PavelStehule v 23. 7. 2025, 11:36</title>
		<link rel="alternate" type="text/html" href="http://postgres.cz/index.php?title=PostgreSQL_SQL_Tricks_II&amp;diff=1389&amp;oldid=prev"/>
		<updated>2025-07-23T11:36:22Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;cs&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Starší verze&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Verze z 23. 7. 2025, 11:36&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l643&quot;&gt;Řádek 643:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Řádek 643:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[PostgreSQL SQL Tricks I|Older tricks]] [[PostgreSQL SQL Tricks III|Newer tricks]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[PostgreSQL SQL Tricks I|Older tricks]] [[PostgreSQL SQL Tricks III|Newer tricks]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-----&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;center&amp;gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;htmlet&amp;gt;wide-banner&amp;lt;/htmlet&amp;gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;/center&amp;gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key pgwiki2-mediawiki-:diff:1.41:old-1383:rev-1389:php=table --&gt;
&lt;/table&gt;</summary>
		<author><name>PavelStehule</name></author>
	</entry>
	<entry>
		<id>http://postgres.cz/index.php?title=PostgreSQL_SQL_Tricks_II&amp;diff=1383&amp;oldid=prev</id>
		<title>PavelStehule v 23. 7. 2025, 11:34</title>
		<link rel="alternate" type="text/html" href="http://postgres.cz/index.php?title=PostgreSQL_SQL_Tricks_II&amp;diff=1383&amp;oldid=prev"/>
		<updated>2025-07-23T11:34:09Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;cs&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Starší verze&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Verze z 23. 7. 2025, 11:34&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;Řádek 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Řádek 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;SQL is a language where one task can be solved multiple ways with different efficiency. You can see effective use of PostgreSQL&amp;#039;s possibilities on this page.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;SQL is a language where one task can be solved multiple ways with different efficiency. You can see effective use of PostgreSQL&amp;#039;s possibilities on this page.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;div style=&quot;padding:20px; float: right;&quot;&amp;gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;div style=&quot; border: solid thin lightgrey; padding:10px;&quot;&amp;gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;htmlet&amp;gt;reklama&amp;lt;/htmlet&amp;gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[PostgreSQL SQL Tricks I|Older tricks]] [[PostgreSQL SQL Tricks III|Newer tricks]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[PostgreSQL SQL Tricks I|Older tricks]] [[PostgreSQL SQL Tricks III|Newer tricks]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>PavelStehule</name></author>
	</entry>
	<entry>
		<id>http://postgres.cz/index.php?title=PostgreSQL_SQL_Tricks_II&amp;diff=541&amp;oldid=prev</id>
		<title>imported&gt;Pavel v 15. 9. 2013, 05:30</title>
		<link rel="alternate" type="text/html" href="http://postgres.cz/index.php?title=PostgreSQL_SQL_Tricks_II&amp;diff=541&amp;oldid=prev"/>
		<updated>2013-09-15T05:30:55Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Nová stránka&lt;/b&gt;&lt;/p&gt;&lt;div&gt;SQL is a language where one task can be solved multiple ways with different efficiency. You can see effective use of PostgreSQL&amp;#039;s possibilities on this page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:20px; float: right;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot; border: solid thin lightgrey; padding:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;htmlet&amp;gt;reklama&amp;lt;/htmlet&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[PostgreSQL SQL Tricks I|Older tricks]] [[PostgreSQL SQL Tricks III|Newer tricks]]&lt;br /&gt;
==subscript shift to zero==&lt;br /&gt;
Implementation of these features is simple in C and it&amp;#039;s little bit slow in PL/pgSQL (based on iterated shift). However, we can use the SQL parser capability to recognize an array range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION shift_idx(anyarray) &lt;br /&gt;
RETURNS anyarray AS $$&lt;br /&gt;
DECLARE &lt;br /&gt;
  mi int := array_upper($1,1); &lt;br /&gt;
  offset int := array_lower($1,1); &lt;br /&gt;
BEGIN&lt;br /&gt;
  RETURN &amp;#039;[0:&amp;#039; || mi - offset || &amp;#039;] = &amp;#039; || $1::varchar; &lt;br /&gt;
END &lt;br /&gt;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;&lt;br /&gt;
CREATE FUNCTION&lt;br /&gt;
&lt;br /&gt;
postgres=# SELECT shift_idx(array[1,2,3]);&lt;br /&gt;
   shift_idx   &lt;br /&gt;
---------------&lt;br /&gt;
 [0:2]={1,2,3}&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
Author: Pavel Stěhule&lt;br /&gt;
&lt;br /&gt;
==Record evolution==&lt;br /&gt;
When we have functions that return a record but cannot use derived tables, we must use following syntax:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE FUNCTION foo(OUT a int, OUT b int, IN c int)&lt;br /&gt;
RETURNS record AS $$&lt;br /&gt;
BEGIN&lt;br /&gt;
  a := c + 1; b := c + 2;&lt;br /&gt;
  RETURN;&lt;br /&gt;
END;&lt;br /&gt;
$$ LANGUAGE plpgsql;&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE t(c int);&lt;br /&gt;
INSERT INTO t VALUES(10),(20);&lt;br /&gt;
&lt;br /&gt;
postgres=# SELECT c, foo(c) FROM t;&lt;br /&gt;
 c  |   foo   &lt;br /&gt;
----+---------&lt;br /&gt;
 10 | (11,12)&lt;br /&gt;
 20 | (21,22)&lt;br /&gt;
(2 rows)&lt;br /&gt;
&lt;br /&gt;
postgres=# SELECT c, (foo(c)).* FROM t;&lt;br /&gt;
 c  | a  | b  &lt;br /&gt;
----+----+----&lt;br /&gt;
 10 | 11 | 12&lt;br /&gt;
 20 | 21 | 22&lt;br /&gt;
(2 rows)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Conversion between hex and dec numbers==&lt;br /&gt;
source: http://www.varlena.com/GeneralBits/104.php.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=# select to_hex(11);&lt;br /&gt;
    to_hex&lt;br /&gt;
   --------&lt;br /&gt;
    b&lt;br /&gt;
   (1 row)&lt;br /&gt;
postgres=# create or replace function to_dec(text) &lt;br /&gt;
           returns integer as $$&lt;br /&gt;
           declare r int; &lt;br /&gt;
           begin &lt;br /&gt;
             execute E&amp;#039;select x\&amp;#039;&amp;#039;||$1|| E&amp;#039;\&amp;#039;::integer&amp;#039; into r; &lt;br /&gt;
             return r; &lt;br /&gt;
           end&lt;br /&gt;
           $$ language plpgsql;&lt;br /&gt;
CREATE FUNCTION&lt;br /&gt;
postgres=# select to_dec(&amp;#039;ff&amp;#039;);&lt;br /&gt;
 to_dec &lt;br /&gt;
--------&lt;br /&gt;
    255&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Faster variant (Michael Glaesemann):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE FUNCTION hex2dec(in_hex TEXT)&lt;br /&gt;
RETURNS INT&lt;br /&gt;
IMMUTABLE STRICT LANGUAGE sql AS $body$&lt;br /&gt;
  SELECT CAST(CAST((&amp;#039;x&amp;#039; || CAST($1 AS text)) AS bit(8)) AS INT);&lt;br /&gt;
$body$;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Variant that is able to handle arbitrary length input (output as varchar, adapt if needed):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION hex2dec (varchar)&lt;br /&gt;
RETURNS varchar as &lt;br /&gt;
$$&lt;br /&gt;
DECLARE &lt;br /&gt;
	_x numeric;&lt;br /&gt;
	_count int;&lt;br /&gt;
	_digit int;&lt;br /&gt;
BEGIN&lt;br /&gt;
	_x := 0;&lt;br /&gt;
	for _count in 1..length($1) loop &lt;br /&gt;
		EXECUTE E&amp;#039;SELECT x\&amp;#039;&amp;#039;||substring($1 from _count for 1)|| E&amp;#039;\&amp;#039;::integer&amp;#039; INTO _digit;&lt;br /&gt;
		_x := _x * 16 + _digit ;&lt;br /&gt;
	end loop;&lt;br /&gt;
	return _x::varchar;&lt;br /&gt;
end&lt;br /&gt;
;&lt;br /&gt;
$$ language plpgsql immutable&lt;br /&gt;
;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fast interval (of time or ip addresses) searching with spatial indexes==&lt;br /&gt;
Searching intervals is usually slow, because the optimizer don&amp;#039;t use an index. The reason lies in the dependency between the start and end columns. One solution is based on spatial indexes: it allows working with two dependent values as if they were a single value:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
postgres=# EXPLAIN ANALYZE SELECT * FROM testip WHERE 19999999 BETWEEN startip AND endip;&lt;br /&gt;
                           QUERY PLAN&lt;br /&gt;
----------------------------------------------------------------&lt;br /&gt;
 Seq Scan on testip  (cost=0.00..19902.00 rows=200814 width=12) (actual time=3.457..434.218 rows=1 loops=1)&lt;br /&gt;
   Filter: ((19999999 &amp;gt;= startip) AND (19999999 &amp;lt;= endip))&lt;br /&gt;
 Total runtime: 434.299 ms&lt;br /&gt;
(3 rows)&lt;br /&gt;
&lt;br /&gt;
Time: 435,865 ms&lt;br /&gt;
&lt;br /&gt;
postgres=# CREATE INDEX ggg ON testip USING gist ((box(point(startip,startip),point(endip,endip))) box_ops);&lt;br /&gt;
CREATE INDEX&lt;br /&gt;
Time: 75530,079 ms&lt;br /&gt;
postgres=# EXPLAIN ANALYZE &lt;br /&gt;
              SELECT * &lt;br /&gt;
                 FROM testip &lt;br /&gt;
                WHERE box(point(startip,startip),point(endip,endip)) @&amp;gt; box(point (19999999,19999999), point(19999999,19999999));&lt;br /&gt;
                                                                                                QUERY PLAN                                                            &lt;br /&gt;
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Bitmap Heap Scan on testip  (cost=60.50..2550.14 rows=1000 width=12) (actual time=0.169..0.172 rows=1 loops=1)&lt;br /&gt;
   Recheck Cond: (box(point((startip)::double precision, (startip)::double precision), point((endip)::double precision, (endip)::double precision)) @&amp;gt; &amp;#039;(19999999,19999999),(19999999,19999999)&amp;#039;::box)&lt;br /&gt;
   -&amp;gt;  Bitmap Index Scan on ggg  (cost=0.00..60.25 rows=1000 width=0) (actual time=0.152..0.152 rows=1 loops=1)&lt;br /&gt;
         Index Cond: (box(point((startip)::double precision, (startip)::double precision), point((endip)::double precision, (endip)::double precision)) @&amp;gt; &amp;#039;(19999999,19999999),(19999999,19999999)&amp;#039;::box)&lt;br /&gt;
 Total runtime: 0.285 ms&lt;br /&gt;
(5 rows)&lt;br /&gt;
&lt;br /&gt;
Time: 2,805 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Short form for insert ROW variables to table==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
postgres=# CREATE TABLE foo(a integer, b integer);&lt;br /&gt;
CREATE TABLE&lt;br /&gt;
postgres=# CREATE OR REPLACE FUNCTION fx() &lt;br /&gt;
           RETURNS void as $$&lt;br /&gt;
             DECLARE r foo; &lt;br /&gt;
           BEGIN &lt;br /&gt;
             SELECT INTO r * FROM foo; &lt;br /&gt;
             INSERT INTO foo VALUES(r.*); &lt;br /&gt;
             RETURN; &lt;br /&gt;
           END; &lt;br /&gt;
           $$ LANGUAGE plpgsql;&lt;br /&gt;
CREATE FUNCTION&lt;br /&gt;
postgres=# SELECT fx();&lt;br /&gt;
 fx &lt;br /&gt;
----&lt;br /&gt;
 &lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ALTER TABLE ALTER COLUMN USING==&lt;br /&gt;
I hadn&amp;#039;t known about the USING clause in ALTER TABLE ALTER COLUMN. I thought the old type had to be castable to the new type. But it&amp;#039;s not true. Czech boolean literals cannot be cast directly to PostgreSQL&amp;#039;s bool type, but, with the USING clause, I can do an ALTER COLUMN TYPE from varchar to bool:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
postgres=# CREATE TABLE foo(a varchar);&lt;br /&gt;
CREATE TABLE&lt;br /&gt;
postgres=# INSERT INTO foo VALUES (&amp;#039;ano&amp;#039;); -- czech yes&lt;br /&gt;
INSERT 0 1&lt;br /&gt;
postgres=# ALTER TABLE foo ALTER COLUMN a TYPE boolean ;&lt;br /&gt;
ERROR:  column &amp;quot;a&amp;quot; cannot be cast to type &amp;quot;pg_catalog.bool&amp;quot;&lt;br /&gt;
postgres=# ALTER TABLE foo &lt;br /&gt;
              ALTER COLUMN a TYPE boolean &lt;br /&gt;
             USING CASE a &lt;br /&gt;
                       WHEN &amp;#039;ano&amp;#039; THEN true &lt;br /&gt;
                       ELSE false END;&lt;br /&gt;
ALTER TABLE&lt;br /&gt;
postgres=# SELECT * FROM foo;&lt;br /&gt;
 a &lt;br /&gt;
---&lt;br /&gt;
 t&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Quote_ident for schema.name==&lt;br /&gt;
Using single quotes is one protection against SQL injection. The function &amp;#039;&amp;#039;quote_ident&amp;#039;&amp;#039; checks its argument and, when the argument contains problematic chars, it returns the argument surrounded by single quotes. It&amp;#039;s quite easy and useful. Problem is with schema.name pair, because the dot is a watched char:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
postgres=# select quote_ident(&amp;#039;public.foo&amp;#039;);&lt;br /&gt;
 quote_ident  &lt;br /&gt;
--------------&lt;br /&gt;
 &amp;quot;public.foo&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
postgres=# select * from &amp;quot;public.foo&amp;quot;;&lt;br /&gt;
ERROR:  relation &amp;quot;public.foo&amp;quot; does not exist&lt;br /&gt;
postgres=# select * from public.&amp;quot;foo&amp;quot;;&lt;br /&gt;
 a &lt;br /&gt;
---&lt;br /&gt;
(0 rows)&lt;br /&gt;
&lt;br /&gt;
postgres=# select * from &amp;quot;public&amp;quot;.&amp;quot;foo&amp;quot;;&lt;br /&gt;
 a &lt;br /&gt;
---&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We can get around this limitation with custom functions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION quote_array(text[]) &lt;br /&gt;
RETURNS text AS $$&lt;br /&gt;
SELECT array_to_string(array(SELECT quote_ident($1[i]) &lt;br /&gt;
                                FROM generate_series(1, array_upper($1,1)) g(i)),&lt;br /&gt;
                       &amp;#039;.&amp;#039;) &lt;br /&gt;
$$ LANGUAGE SQL IMMUTABLE;&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION quote_schema_ident(text) &lt;br /&gt;
RETURNS text AS $$&lt;br /&gt;
SELECT quote_array(string_to_array($1,&amp;#039;.&amp;#039;))&lt;br /&gt;
$$ LANGUAGE SQL IMMUTABLE;&lt;br /&gt;
&lt;br /&gt;
postgres=# select quote_schema_ident(&amp;#039;public.foo tab&amp;#039;);&lt;br /&gt;
 quote_schema_ident &lt;br /&gt;
--------------------&lt;br /&gt;
 public.&amp;quot;foo tab&amp;quot;&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Autor: [[Pavel Stehule]].&lt;br /&gt;
&lt;br /&gt;
==Fast searching of longer prefix==&lt;br /&gt;
Searching longest prefix is common task - mainly in communications. We search for the longest prefix for some number from from set of prefixes. I solved this task some years ago with stored procedure and modified method of halving of interval. Maybe little bit slower but simple and robust method was described by Hubert Lubaciewski ([http://www.depesz.com/index.php/2008/03/04/searching-for-longest-prefix/#more-1176 Depesz]).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--table contains about 5000 prefixes&lt;br /&gt;
postgres=# select * from prefixesx limit 5;&lt;br /&gt;
   costcode_name    | costcode &lt;br /&gt;
--------------------+----------&lt;br /&gt;
 Afghanistan        | 93&lt;br /&gt;
 Afghanistan Mobile | 9370&lt;br /&gt;
 Afghanistan Mobile | 9379&lt;br /&gt;
 Afghanistan Mobile | 9380&lt;br /&gt;
 Alaska (USA)       | 1907&lt;br /&gt;
(5 rows)&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
Simple but slow solution with LIKE:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
postgres=# SELECT * &lt;br /&gt;
              FROM prefixesx &lt;br /&gt;
             WHERE &amp;#039;420724181000&amp;#039; LIKE costcode || &amp;#039;%&amp;#039; &lt;br /&gt;
             ORDER BY length(costcode) DESC &lt;br /&gt;
             LIMIT 1;&lt;br /&gt;
          costcode_name          | costcode &lt;br /&gt;
---------------------------------+----------&lt;br /&gt;
 Czech Republic Mobile - EuroTel | 42072&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Fast solution is generating all possible prefixes from number and search this prefixes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION prefixes(varchar) &lt;br /&gt;
RETURNS varchar[] AS $$&lt;br /&gt;
SELECT ARRAY(SELECT substring($1 FROM 1 FOR i) &lt;br /&gt;
                FROM generate_series(1, length($1)) g(i))::varchar[]; &lt;br /&gt;
$$ LANGUAGE sql IMMUTABLE;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
and use query:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
postgres=# SELECT * &lt;br /&gt;
              FROM prefixesx &lt;br /&gt;
             WHERE costcode = ANY (prefixes(&amp;#039;420724191000&amp;#039;)) &lt;br /&gt;
             ORDER BY length(costcode) DESC &lt;br /&gt;
             LIMIT 1;&lt;br /&gt;
          costcode_name          | costcode &lt;br /&gt;
---------------------------------+----------&lt;br /&gt;
 Czech Republic Mobile - EuroTel | 42072&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On 5000 rows is this query 4 times faster than LIKE.&lt;br /&gt;
&lt;br /&gt;
Little bit slower is query with LIKE and LIKE firstchar || %&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT * &lt;br /&gt;
   FROM prefixesx&lt;br /&gt;
  WHERE &amp;#039;420724181000&amp;#039; LIKE costcode || &amp;#039;%&amp;#039;&lt;br /&gt;
    AND costcode LIKE substring(&amp;#039;420724191000&amp;#039; FROM 1 FOR 1) || &amp;#039;%&amp;#039;  &lt;br /&gt;
  ORDER BY length(costcode) DESC &lt;br /&gt;
  LIMIT 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Get count of substrings in string==&lt;br /&gt;
This function is based on popular trick - using replace and length function without cycle, that is typical for interprets where built-in functions are faster than iteration:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION CountInString(text,text)&lt;br /&gt;
RETURNS integer AS $$&lt;br /&gt;
 SELECT(Length($1) - Length(REPLACE($1, $2, &amp;#039;&amp;#039;))) / Length($2) ;&lt;br /&gt;
$$ LANGUAGE SQL IMMUTABLE;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Sent by Rodrigo E. De León Plicet. Another my (array based) solution:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION CountInString(text, text) &lt;br /&gt;
RETURNS integer AS $$&lt;br /&gt;
  SELECT Array_upper(String_to_array($1,$2),1) - 1;&lt;br /&gt;
$$ LANGUAGE SQL IMMUTABLE;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Timestamp recalculation for different timezone and its indexing==&lt;br /&gt;
The simplest specification of time at some timezone is using AT TIME ZONE operator. We can&amp;#039;t indexing timestamp with timezone, because we can change current timezone, so we can create index only for timestamp at some specified timezone. Source: pgsql-general, Tom Lane&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE INDEX created_tz_paris ON data((created_on AT TIME ZONE &amp;#039;Europe/Paris&amp;#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Using IMMUTABLE functions as hints for the optimizer==&lt;br /&gt;
For highly specific data distributions, we can have a problem with prediction and generation of suboptimal execution plans. These problems we can solve by breaking a SQL query into more dependent queries and evaluating step by step. The following queries use real results (not estimations) precedent queries, and queries are executed optimally. Tom Lane&amp;#039;s proposal is based on using IMMUTABLE functions that are evaluated before generating an execution plan:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION getTypesLieuFromTheme(codeTheme text) &lt;br /&gt;
RETURNS text[] AS $f$&lt;br /&gt;
SELECT ARRAY(SELECT codetylieu::text FROM rubtylieu WHERE codeth = $1);&lt;br /&gt;
$f$ LANGUAGE SQL IMMUTABLE;&lt;br /&gt;
&lt;br /&gt;
in query&lt;br /&gt;
SELECT ...&lt;br /&gt;
  WHERE ... AND gl.codetylieu = ANY(getTypesLieuFromTheme(&amp;#039;RES&amp;#039;))&lt;br /&gt;
&lt;br /&gt;
look execution plan doesn&amp;#039;t contain function call and query to table rubtylieu too&lt;br /&gt;
-&amp;gt;  Bitmap Heap Scan on genrelieu gl (cost=2.23..6.22 rows=88 width=4) (actual time=0.022..0.075 rows=88 loops=1)&lt;br /&gt;
       Recheck Cond: ((codetylieu)::text = ANY (&amp;#039;{RES}&amp;#039;::text[]))&lt;br /&gt;
       -&amp;gt;  Bitmap Index Scan on ind_genrelieu2 (cost=0.00..2.21 rows=88 width=0) (actual time=0.016..0.016 rows=88 loops=1)&lt;br /&gt;
                Index Cond: ((codetylieu)::text = ANY (&amp;#039;{RES}&amp;#039;::text[]))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use this trick as last step. Test, please, by increasing the statistic number beforehand.&lt;br /&gt;
&lt;br /&gt;
==Autonomous transaction in PostgreSQL==&lt;br /&gt;
Autonomous transaction is usable feature mainly for logging. This feature isn&amp;#039;t supported in PostgreSQL yet. With untrusted languages we are able to emulate it. You can see solution by Jon Roberts.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION fn_log_error(p_function varchar, p_location int, p_error varchar) &lt;br /&gt;
RETURNS void AS $$&lt;br /&gt;
DECLARE&lt;br /&gt;
  v_sql varchar;&lt;br /&gt;
  v_return varchar;&lt;br /&gt;
  v_error varchar;&lt;br /&gt;
BEGIN&lt;br /&gt;
  PERFORM dblink_connect(&amp;#039;connection_name&amp;#039;, &amp;#039;dbname=...&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
  v_sql := &amp;#039;INSERT INTO error_log (function_name, location, error_message, error_time) &amp;#039;&lt;br /&gt;
           || &amp;#039;VALUES (&amp;#039;&amp;#039;&amp;#039; || p_function_name || &amp;#039;&amp;#039;&amp;#039;, &amp;#039; &lt;br /&gt;
           || p_location || &amp;#039;, &amp;#039;&amp;#039;&amp;#039; || p_error || &amp;#039;&amp;#039;&amp;#039;, clock_timestamp())&amp;#039;;&lt;br /&gt;
  SELECT INTO v_return * &lt;br /&gt;
     FROM dblink_exec(&amp;#039;connection_name&amp;#039;, v_sql, false);&lt;br /&gt;
&lt;br /&gt;
  --get the error message&lt;br /&gt;
  SELECT INTO v_error * &lt;br /&gt;
     FROM dblink_error_message(&amp;#039;connection_name&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
  IF position(&amp;#039;ERROR&amp;#039; in v_error) &amp;gt; 0 OR position(&amp;#039;WARNING&amp;#039; in v_error) &amp;gt; 0 THEN&lt;br /&gt;
    RAISE EXCEPTION &amp;#039;%&amp;#039;, v_error;&lt;br /&gt;
  END IF;&lt;br /&gt;
&lt;br /&gt;
  PERFORM dblink_disconnect(&amp;#039;connection_name&amp;#039;);&lt;br /&gt;
EXCEPTION&lt;br /&gt;
  WHEN others THEN&lt;br /&gt;
    PERFORM dblink_disconnect(&amp;#039;connection_name&amp;#039;);&lt;br /&gt;
    RAISE EXCEPTION &amp;#039;(%)&amp;#039;, SQLERRM;&lt;br /&gt;
END;&lt;br /&gt;
$$ LANGUAGE plpgsql SECURITY DEFINER;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Optimization of repetitive assignment to varchar variable with arrays==&lt;br /&gt;
plpgsql isn&amp;#039;t a good language for intensive non SQL operations. It&amp;#039;s best as glue for SQL statements or for prototyping. But sometimes plperl or plpython can be significantly faster. Plpgsql does not like cumulative iterations over varchar or array variables. When we can&amp;#039;t use Perl, ..  we could use SQL:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION SlowList(int) -- slow function, usable for N &amp;lt;= 100&lt;br /&gt;
RETURNS varchar AS $$&lt;br /&gt;
DECLARE s varchar = &amp;#039;&amp;#039;;&lt;br /&gt;
BEGIN&lt;br /&gt;
  FOR i IN 1..$1 LOOP&lt;br /&gt;
    s := &amp;#039;&amp;lt;item&amp;gt;&amp;#039; || i || &amp;#039;&amp;lt;/item&amp;gt;&amp;#039;;  -- slow is s := s || ..&lt;br /&gt;
  END LOOP;&lt;br /&gt;
  RETURN s;&lt;br /&gt;
END; $$ LANGUAGE plpgsql IMMUTABLE;&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTON FastList(int) -- fast function&lt;br /&gt;
RETURNS varchar AS $$&lt;br /&gt;
BEGIN&lt;br /&gt;
  RETURN array_to_string(ARRAY(SELECT &amp;#039;&amp;lt;item&amp;gt;&amp;#039; || i || &amp;#039;&amp;lt;/item&amp;gt;&amp;#039;&lt;br /&gt;
                                  FROM generate_series(1, $1) g(i)),&lt;br /&gt;
                         &amp;#039;&amp;#039;);&lt;br /&gt;
END; $$ LANGUAGE plpgsql IMMUTABLE;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For N &amp;lt; 100 execution time is less then 4ms (so isn&amp;#039;t any reason for dirty trick). For bigger N is execution time different (SlowList(10000) - 4000ms, FastList(10000) - 52ms). Author - Pavel Stěhule.&lt;br /&gt;
&lt;br /&gt;
==Use IS DISTINCT FROM without COALESCE==&lt;br /&gt;
Sim Zacks reported slow queries after migration to 8.2.4. This version has problem with prediction of result of expression COALESCE(column, false) = false, and then execution plan is suboptimal. After correction PostgreSQL choose optimal execution plan.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT ...&lt;br /&gt;
   FROM some_tab&lt;br /&gt;
        LEFT JOIN&lt;br /&gt;
        some_tab2&lt;br /&gt;
        ON sometab2.col IS DISTINCT FROM true; --&amp;gt; join false or NULL &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
So don&amp;#039;t use COALESCE in WHERE clause&lt;br /&gt;
&lt;br /&gt;
Next week somebody reported similar problem:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-- execution plan is suboptimal&lt;br /&gt;
((COALESCE((at_type)::integer, 1) = 1) AND (COALESCE(at_language, 0::numeric) = 0::numeric))&lt;br /&gt;
&lt;br /&gt;
-- execution plan is optimal&lt;br /&gt;
(at_type = 1 or at_type is null) AND (at_language = 0 or at_language is null)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Port to Oracle, problems with to_date function==&lt;br /&gt;
Peter Eisentraut reported incompatibility to_date function between PostreSQL and Oracle.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SQL&amp;gt; select to_date(&amp;#039;31-DEC-200700:00:00&amp;#039;, &amp;#039;dd-mon-yyyy hh24:mi:ss&amp;#039;) from&lt;br /&gt;
dual;&lt;br /&gt;
&lt;br /&gt;
TO_DATE(&amp;#039;&lt;br /&gt;
---------&lt;br /&gt;
31-DEC-07&lt;br /&gt;
&lt;br /&gt;
On PostgreSQL:&lt;br /&gt;
&lt;br /&gt;
select to_date(&amp;#039;31-DEC-200700:00:00&amp;#039;, &amp;#039;dd-mon-yyyy hh24:mi:ss&amp;#039;);&lt;br /&gt;
  to_date&lt;br /&gt;
--------------&lt;br /&gt;
 200700-12-31&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Oracle ignores spaces in format string, but PostgreSQL requires exact format. This behavior can be changed in custom function that drops spaces (Author: Jon Roberts):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION fn_to_date(p_date varchar, p_format varchar)&lt;br /&gt;
RETURNS timestamp AS $$&lt;br /&gt;
 SELECT to_timestamp(replace($1, &amp;#039; &amp;#039;, &amp;#039;&amp;#039;), replace($2, &amp;#039; &amp;#039;, &amp;#039;&amp;#039;));&lt;br /&gt;
$$ LANGUAGE SQL STRICT IMMUTABLE;&lt;br /&gt;
&lt;br /&gt;
# select fn_to_date(&amp;#039;31-DEC-200700:00:00&amp;#039;, &amp;#039;dd-mon-yyyy hh24:mi:ss&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
    fn_to_date&lt;br /&gt;
---------------------&lt;br /&gt;
 2007-12-31 00:00:00&lt;br /&gt;
(1 row)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Identification and correction of wrong chars in PostgreSQL dump==&lt;br /&gt;
8.2 is stricter than 8.1 for correct chars in dump. Reason is in SQL injection security fix (via incorrect UTF8 chars). This change of behavior can cause problems with migration. Fix is simple. We have to find wrong char and fix it. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ iconv -f utf-8 -t utf-8 dump.sql &amp;gt; /dev/null&lt;br /&gt;
iconv: illegal input sequence at position 1000&lt;br /&gt;
$ head -c 1010 dump.sql | tail -c 20 | od -c&lt;br /&gt;
0000000 h . B u t i s n 222 t i t&lt;br /&gt;
0000020 h i s ?&lt;br /&gt;
0000024&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Source: http://lca2007.linux.org.au/att_data/Miniconfs(2f)PostgreSQL/attachments/professional.pdf&lt;br /&gt;
&lt;br /&gt;
==Be carefull when using the NOT IN operator with NULL==&lt;br /&gt;
Some SQL developer dislike NULL. Other like it. I like it, too. NULL is necessary and saves a lot of work. NULL in a result expression clearly signals some problem in the input data. People who dislike NULL don&amp;#039;t understand it and use the following argument, citing an &amp;quot;anomaly&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
postgres=# SELECT * &lt;br /&gt;
              FROM (VALUES(10),(20),(30)) v(a) &lt;br /&gt;
             WHERE a IN (10, 20, NULL); --&amp;gt; all is ok&lt;br /&gt;
 a  &lt;br /&gt;
----&lt;br /&gt;
 10&lt;br /&gt;
 20&lt;br /&gt;
(2 rows)&lt;br /&gt;
&lt;br /&gt;
postgres=# SELECT * &lt;br /&gt;
              FROM (VALUES(10),(20),(30)) v(a) &lt;br /&gt;
             WHERE a NOT IN (10, 20, NULL);&lt;br /&gt;
 a &lt;br /&gt;
---&lt;br /&gt;
(0 rows) --&amp;gt; anomaly, expects 30&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
But it isn&amp;#039;t an anomaly. The NOT IN operator checks each item of a list, because the left-hand value must be different than all of them. Since we can never have a comparison with NULL that results in anything but NULL, no value can fulfill this predicate.&lt;br /&gt;
&lt;br /&gt;
==Fast specification of first rows of some table field==&lt;br /&gt;
My task is specific. I have address book with 100 000 items and I have to get all first chars of surnames. This task is one from a few tasks, where correlated subquery is faster than everything else. Because seq scan and agg function need scan all 100 000 records, but correlated subquery need only 32 access to functional index:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT * &lt;br /&gt;
   FROM (&lt;br /&gt;
         SELECT substring(&amp;#039;abcdefghijklmnopqrstuvwxyzěščřžýáíé&amp;#039; &lt;br /&gt;
                          FROM i For 1) &lt;br /&gt;
            FROM generate_series(1,32) g(i)&lt;br /&gt;
        ) p(onechar) &lt;br /&gt;
  WHERE EXISTS(&lt;br /&gt;
               SELECT 1 &lt;br /&gt;
                  FROM address_book &lt;br /&gt;
                 WHERE substring(surname from 1 for 1) = p.onechar  &lt;br /&gt;
                   and active&lt;br /&gt;
              );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Version for support czech char CH (and some others: úůňľó):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   SELECT * &lt;br /&gt;
   FROM&lt;br /&gt;
     ( &lt;br /&gt;
         SELECT substring(&amp;#039;abcdefghijklmnopqrstuvwxyzěščřžýáíéúůňľó&amp;#039; FROM i For 1) FROM generate_series(1,40) g(i) UNION SELECT &amp;#039;ch&amp;#039; &lt;br /&gt;
     ) p(onechar) &lt;br /&gt;
   WHERE&lt;br /&gt;
     EXISTS( SELECT 1 FROM a_osoba WHERE lower(substring(prijmeni from 1 for char_length(p.onechar))) = p.onechar );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==An employee with highest compensation==&lt;br /&gt;
It&amp;#039;s typical school query: select the highest-paid employees in some group. This query can be solved with derivated table or with correlated subquery. We could use the nonstandard clause DISTINCT ON in PostgreSQL:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
postgres=# SELECT * FROM employees ;&lt;br /&gt;
   name    | surname   | department | payment  &lt;br /&gt;
-----------+-----------+------------+-------&lt;br /&gt;
 Pavel     | Stehule   |          1 | 10000&lt;br /&gt;
 Zdenek    | Stehule   |          1 |  9000&lt;br /&gt;
 Vladimira | Stehulova |          2 |  9000&lt;br /&gt;
(3 rows)&lt;br /&gt;
&lt;br /&gt;
postgres=# SELECT DISTINCT ON department * &lt;br /&gt;
              FROM employees &lt;br /&gt;
             ORDER BY department, payment DESC;&lt;br /&gt;
   name    | surname   | department | payment  &lt;br /&gt;
-----------+-----------+------------+-------&lt;br /&gt;
 Pavel     | Stehule   |          1 | 10000&lt;br /&gt;
 Vladimira | Stehulova |          2 |  9000&lt;br /&gt;
(2 rows)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Attention, DISTINCT ON isn&amp;#039;t portable. A big disadvantage of this solution is that it shows only one person from every department, even when more employees has the same, highest, payment, yielding an incomplete result.&lt;br /&gt;
&lt;br /&gt;
==Any other session variables==&lt;br /&gt;
PostgreSQL doesn&amp;#039;t support server session variables. This mean, so we have to write stored procedures more often, because there are variables. Some substitution is module variables. These variables has to allowed in configuration. Sent by Andreas Kretschmer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
- define in your postgresql.conf:&lt;br /&gt;
 custom_variable_classes = &amp;#039;myvar&amp;#039;&lt;br /&gt;
&lt;br /&gt;
- use within psql:&lt;br /&gt;
&lt;br /&gt;
test=# set myvar.benutzer = &amp;#039;foo&amp;#039;;&lt;br /&gt;
SET&lt;br /&gt;
test=*# select * from foo;&lt;br /&gt;
 id | name&lt;br /&gt;
----+------&lt;br /&gt;
 1 | foo&lt;br /&gt;
 2 | bar&lt;br /&gt;
(2 rows)&lt;br /&gt;
&lt;br /&gt;
test=*# select * from foo where name=current_setting(&amp;#039;myvar.benutzer&amp;#039;);&lt;br /&gt;
 id | name&lt;br /&gt;
----+------&lt;br /&gt;
 1 | foo&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
test=*# set myvar.benutzer = &amp;#039;none&amp;#039;;&lt;br /&gt;
SET&lt;br /&gt;
test=*# select * from foo where name=current_setting(&amp;#039;myvar.benutzer&amp;#039;);&lt;br /&gt;
 id | name&lt;br /&gt;
----+------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==xpath function indexing==&lt;br /&gt;
8.3 has integrated xpath function. There is gap in XML support, because XML type isn&amp;#039;t supported with GIST or GIN index. So xpath function returns array of xml values. But we can write custom casting to int array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION xml_list_to_int(xml[])&lt;br /&gt;
RETURNS int[] AS $$&lt;br /&gt;
SELECT ARRAY(SELECT to_number(($1[i])::text,&amp;#039;999999.99&amp;#039;)::int&lt;br /&gt;
                FROM generate_series(1, array_upper($1,1)) g(i))&lt;br /&gt;
$$ LANGUAGE SQL IMMUTABLE;&lt;br /&gt;
&lt;br /&gt;
CREATE CAST (xml[] AS int[]) WITH FUNCTION xml_list_to_int(xml[]);&lt;br /&gt;
&lt;br /&gt;
-- array of integers are supported with GIST&lt;br /&gt;
CREATE INDEX fx ON foo USING&lt;br /&gt;
GIN((xpath(&amp;#039;//id/text()&amp;#039;,order_in_xml)::int[]));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== psql together with less ==&lt;br /&gt;
psql has paging support, but it isn&amp;#039;t comparable with the options offered by &amp;lt;code&amp;gt;less&amp;lt;/code&amp;gt;. Here is example on how to setup psql to use &amp;lt;code&amp;gt;less&amp;lt;/code&amp;gt; as the pager. Author: Merlin Moncure&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#to profile&lt;br /&gt;
export PAGER=less&lt;br /&gt;
export LESS=&amp;quot;-iMSx4 -FX&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#to .psqlrc&lt;br /&gt;
\timing&lt;br /&gt;
\pset pager always&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Intersection of arrays ==&lt;br /&gt;
Very nice trick by [http://people.planetpostgresql.org/dfetter/ David Fetter]. It&amp;#039;s based well known trick ([[#General array sort|universal sort of array]]):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION array_intersect(ANYARRAY, ANYARRAY)&lt;br /&gt;
RETURNS ANYARRAY&lt;br /&gt;
LANGUAGE SQL&lt;br /&gt;
AS $$&lt;br /&gt;
  SELECT ARRAY(&lt;br /&gt;
               SELECT $1[i] AS &amp;quot;the_intersection&amp;quot;&lt;br /&gt;
                  FROM generate_series(&lt;br /&gt;
                                       array_lower($1,1),&lt;br /&gt;
                                       array_upper($1,1)&lt;br /&gt;
                                      ) AS i&lt;br /&gt;
               INTERSECT&lt;br /&gt;
               SELECT $2[j] AS &amp;quot;the_intersection&amp;quot;&lt;br /&gt;
                  FROM generate_series(&lt;br /&gt;
                                       array_lower($2,1),&lt;br /&gt;
                                       array_upper($2,1)&lt;br /&gt;
                                      ) AS j&lt;br /&gt;
              );&lt;br /&gt;
$$;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An alternative and possibly faster way:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION array_intersect(ANYARRAY, ANYARRAY)&lt;br /&gt;
RETURNS ANYARRAY&lt;br /&gt;
LANGUAGE SQL&lt;br /&gt;
AS $$&lt;br /&gt;
  SELECT ARRAY(SELECT UNNEST($1) INTERSECT SELECT UNNEST($2))&lt;br /&gt;
$$;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== VOID function in SQL language==&lt;br /&gt;
SQL functions can contain only SQL statements. The results of the last statements are results of the functions. The type of a result have to be compatible with the function&amp;#039;s type. Because VOID is fictive type, no statement can return this type with one exception. We can cast NULL to VOID.&lt;br /&gt;
&lt;br /&gt;
note: void returning functions are not allowed to be used through the binary protocol&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE OR REPLACE FUNCTION none() &lt;br /&gt;
RETURNS VOID AS $$ SELECT NULL::VOID; $$&lt;br /&gt;
LANGUAGE SQL;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fast select of next row ==&lt;br /&gt;
For older application (ISAM appliaction works on series of rows) we have be able to search next row specified with some combination of values (a1, b1, c1).&lt;br /&gt;
Traditional solution:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT * &lt;br /&gt;
   FROM data&lt;br /&gt;
  WHERE (a &amp;gt; a1)&lt;br /&gt;
     OR (a = a1 AND b &amp;gt; b1)&lt;br /&gt;
     OR (a = a1 AND b = b1 AND c &amp;gt; c1)&lt;br /&gt;
  ORDER BY a, b, c&lt;br /&gt;
  LIMIT 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Merlin Moncure noted simplified form that use row equation. This form is more readable and allows using multicolumn index:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT *&lt;br /&gt;
   FROM data&lt;br /&gt;
  WHERE (a, b, c) &amp;gt; (a1, b1, c1)&lt;br /&gt;
  ORDER BY a, b, c&lt;br /&gt;
  LIMIT 1; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
ISAM access downgrade SQL serer performance. For effective SQL we have to operate over sets, but when we cannot rewrite application, we have not choice.&lt;br /&gt;
&lt;br /&gt;
[[PostgreSQL SQL Tricks I|Older tricks]] [[PostgreSQL SQL Tricks III|Newer tricks]]&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
&amp;lt;htmlet&amp;gt;wide-banner&amp;lt;/htmlet&amp;gt;&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;/div&gt;</summary>
		<author><name>imported&gt;Pavel</name></author>
	</entry>
</feed>