Ett mycket enkelt exempel skulle vara:
> SELECT * FROM tab ORDER BY col USING <
Men det här är tråkigt, för det här är inget du inte kan få med den traditionella ORDER BY col ASC
.
Standardkatalogen nämner inte heller något spännande om konstiga jämförelsefunktioner/operatorer. Du kan få en lista över dem:
> 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);
Du kommer att märka att det mestadels finns <
och > funktioner för primitiva typer som
heltal
, datum
etc och lite mer för arrayer och vektorer och så vidare. Ingen av dessa operatörer hjälper dig att få en anpassad beställning.
I de flesta fall där anpassad beställning krävs kan du komma undan med något som ... BESTÄLL MED somefunc(tabellkolumn) ...
där somefunc
kartlägger värdena på lämpligt sätt. Eftersom det fungerar med varje databas är detta också det vanligaste sättet. För enkla saker kan du till och med skriva ett uttryck istället för en anpassad funktion.
Växlar upp
BESTÄLL GENOM ... ANVÄNDA
är vettigt i flera fall:
- Beställningen är så ovanlig att
somefunc
tricket fungerar inte. - Du arbetar med en icke-primitiv typ (som
point
,cirkel
eller imaginära siffror) och du vill inte upprepa dig själv i dina frågor med konstiga beräkningar. - Datauppsättningen du vill sortera är så stor att stöd av ett index önskas eller till och med krävs.
Jag kommer att fokusera på de komplexa datatyperna:ofta finns det mer än ett sätt att sortera dem på ett rimligt sätt. Ett bra exempel är point
:Du kan "beställa" dem efter avståndet till (0,0), eller med x först, sedan av y eller bara av y eller något annat du vill.
PostgreSQL har såklart fördefinierade operatorer för punkt
:
> CREATE TABLE p ( p point );
> SELECT p <-> point(0,0) FROM p;
Men ingen av dem förklaras användbara för ORDER BY
som standard (se ovan):
> 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.
Enkla operatorer för point
är operatorerna "under" och "ovan" <^
och >^
. De jämför helt enkelt y
del av poängen. Men:
> SELECT * FROM p ORDER BY p USING >^;
ERROR: operator > is not a valid ordering operator
TIP: Ordering operators must be "<" or ">" members of __btree__ operator families.
BESTÄLL GENOM
kräver en operator med definierad semantik:Uppenbarligen måste den vara en binär operator, den måste acceptera samma typ som argument och den måste returnera boolesk. Jag tror att det också måste vara transitivt (om a btree -indexbeställning. Detta förklarar de konstiga felmeddelandena som innehåller referensen till btree .
BESTÄLL GENOM
kräver inte bara en operatör ska definieras men en operatörsklass och en operatörsfamilj . Medan man kunde implementera sortering med endast en operatör, PostgreSQL försöker sortera effektivt och minimera jämförelser. Därför används flera operatorer även när du bara anger en - de andra måste följa vissa matematiska begränsningar - jag har redan nämnt transitivitet, men det finns fler.
Växlar upp
Låt oss definiera något lämpligt:En operator för punkter som endast jämför y
del.
Det första steget är att skapa en anpassad operatörsfamilj som kan användas av btree indexåtkomstmetod. se
> CREATE OPERATOR FAMILY xyzfam USING btree; -- superuser access required!
CREATE OPERATOR FAMILY
Därefter måste vi tillhandahålla en komparatorfunktion som returnerar -1, 0, +1 när vi jämför två punkter. Denna funktion KOMMER bli uppringd internt!
> CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int
AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql;
CREATE FUNCTION
Därefter definierar vi operatörsklassen för familjen. Se manualen för en förklaring av siffrorna.
> CREATE OPERATOR CLASS xyz_ops FOR TYPE point USING btree FAMILY xyzfam AS
OPERATOR 1 <^ ,
OPERATOR 3 ?- ,
OPERATOR 5 >^ ,
FUNCTION 1 xyz_v_cmp(point, point) ;
CREATE OPERATOR CLASS
Detta steg kombinerar flera operatorer och funktioner och definierar även deras relation och betydelse. Till exempel OPERATOR 1
betyder:Detta är operatorn för mindre än
tester.
Nu är operatorerna <^
och >^
kan användas i ORDER BY USING
:
> INSERT INTO p SELECT point(floor(random()*100), floor(random()*100)) FROM generate_series(1, 5);
INSERT 0 5
> SELECT * FROM p ORDER BY p USING >^;
p
---------
(17,8)
(74,57)
(59,65)
(0,87)
(58,91)
Voila - sorterat efter y .
För att sammanfatta det: BESTÄLL GENOM ... ANVÄNDA
är en intressant look under huven på PostgreSQL. Men inget du kommer att kräva när som helst snart om du inte arbetar i mycket specifika områden av databasteknik.
Ett annat exempel finns i Postgres docs. med källkod för exemplet här och här. Detta exempel visar också hur man skapar operatorerna.