Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>A very simple example would be:</p> <pre><code>&gt; SELECT * FROM tab ORDER BY col USING &lt; </code></pre> <p>But this is boring, because this is nothing you can't get with the traditional <code>ORDER BY col ASC</code>. </p> <p>Also the standard catalog doesn't mention anything exciting about strange comparison functions/operators. You can get a list of them:</p> <pre><code> &gt; SELECT amoplefttype::regtype, amoprighttype::regtype, amopopr::regoper FROM pg_am JOIN pg_amop ON pg_am.oid = pg_amop.amopmethod WHERE amname = 'btree' AND amopstrategy IN (1,5); </code></pre> <p>You will notice, that there are mostly <code>&lt;</code> and <code>&gt;</code> functions for primitive types like <code>integer</code>, <code>date</code> etc and some more for arrays and vectors and so on. None of these operators will help you to get a custom ordering.</p> <p>In <em>most</em> cases where custom ordering is required you can get away using something like <code>... ORDER BY somefunc(tablecolumn) ...</code> where <code>somefunc</code> maps the values appropriately. Because that works with every database this is also the most common way. For simple things you can even write an expression instead of a custom function.</p> <p><em>Switching gears up</em></p> <p><code>ORDER BY ... USING</code> makes sense in several cases:</p> <ul> <li>The ordering is so uncommon, that the <code>somefunc</code> trick doesn't work.</li> <li>You work with a non-primitive type (like <code>point</code>, <code>circle</code> or imaginary numbers) and you don't want to repeat yourself in your queries with strange calculations.</li> <li>The dataset you want to sort is so large, that support by an index is desired or even required.</li> </ul> <p>I will focus on the complex datatypes: often there is more than one way to sort them in a reasonable way. A good example is <code>point</code>: You can "order" them by the distance to (0,0), or by <em>x</em> first, then by <em>y</em> or just by <em>y</em> or anything else you want.</p> <p>Of course, PostgreSQL <em>has</em> predefined operators for <code>point</code>:</p> <pre><code> &gt; CREATE TABLE p ( p point ); &gt; SELECT p &lt;-&gt; point(0,0) FROM p; </code></pre> <p>But <em>none</em> of them is declared usable for <code>ORDER BY</code> by default (see above):</p> <pre><code> &gt; SELECT * FROM p ORDER BY p; ERROR: could not identify an ordering operator for type point TIP: Use an explicit ordering operator or modify the query. </code></pre> <p>Simple operators for <code>point</code> are the "below" and "above" operators <code>&lt;^</code> and <code>&gt;^</code>. They compare simply the <code>y</code> part of the point. But:</p> <pre><code> &gt; SELECT * FROM p ORDER BY p USING &gt;^; ERROR: operator &gt; is not a valid ordering operator TIP: Ordering operators must be "&lt;" or "&gt;" members of __btree__ operator families. </code></pre> <p><code>ORDER BY USING</code> requires an operator with defined semantics: Obviously it must be a binary operator, it must accept the same type as arguments and it must return boolean. I think it must also be transitive (if a &lt; b and b &lt; c then a &lt; c). There may be more requirements. But all these requirements are also necessary for proper <strong>btree</strong>-index ordering. This explains the strange error messages containing the reference to <strong>btree</strong>. </p> <p><code>ORDER BY USING</code> also requires not just <em>one operator</em> to be defined but an <em>operator class</em> and an <em>operator family</em>. While one <em>could</em> implement sorting with only one operator, PostgreSQL tries to sort efficiently and minimize comparisons. Therefore, several operators are used even when you specify only one - the others must adhere to certain mathematical constraints - I've already mentioned transitivity, but there are more.</p> <p><em>Switching Gears up</em></p> <p>Let's define something suitable: An operator for points which compares only the <code>y</code> part.</p> <p>The first step is to create a custom operator family which can be used by the <strong>btree</strong> index access method. <a href="http://www.postgresql.org/docs/9.1/interactive/xindex.html" rel="noreferrer">see</a></p> <pre><code> &gt; CREATE OPERATOR FAMILY xyzfam USING btree; -- superuser access required! CREATE OPERATOR FAMILY </code></pre> <p>Next we must provide a comparator function which returns -1, 0, +1 when comparing two points. This function <em>WILL</em> be called internally!</p> <pre><code> &gt; CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql; CREATE FUNCTION </code></pre> <p>Next we define the operator class for the family. <a href="http://www.postgresql.org/docs/9.1/interactive/xindex.html" rel="noreferrer">See the manual</a> for an explanation of the numbers.</p> <pre><code> &gt; CREATE OPERATOR CLASS xyz_ops FOR TYPE point USING btree FAMILY xyzfam AS OPERATOR 1 &lt;^ , OPERATOR 3 ?- , OPERATOR 5 &gt;^ , FUNCTION 1 xyz_v_cmp(point, point) ; CREATE OPERATOR CLASS </code></pre> <p>This step combines several operators and functions and also defines their relationship and meaning. For example <code>OPERATOR 1</code> means: This is the operator for <code>less-than</code> tests.</p> <p>Now the operators <code>&lt;^</code> and '>^' can be used in <code>ORDER BY USING</code>:</p> <pre><code>&gt; INSERT INTO p SELECT point(floor(random()*100), floor(random()*100)) FROM generate_series(1, 5); INSERT 0 5 &gt; SELECT * FROM p ORDER BY p USING &gt;^; p --------- (17,8) (74,57) (59,65) (0,87) (58,91) </code></pre> <p>Voila - sorted by <em>y</em>.</p> <p><strong>To sum it up:</strong> <code>ORDER BY ... USING</code> is an interesting look under the hood of PostgreSQL. But nothing you will require anytime soon unless you work in <em>very</em> specific areas of database technology.</p> <p>Another example can be found <a href="https://www.postgresql.org/docs/9.1/static/xindex.html#XINDEX-EXAMPLE" rel="noreferrer">in the Postgres docs.</a> with source code for the example <a href="https://github.com/postgres/postgres/blob/master/src/tutorial/complex.source" rel="noreferrer">here</a> and <a href="https://github.com/postgres/postgres/blob/master/src/tutorial/complex.c" rel="noreferrer">here</a>. This example also shows how to create the operators.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload