Un ejemplo muy simple sería:
> SELECT * FROM tab ORDER BY col USING <
Pero esto es aburrido, porque esto no es nada que no se puede conseguir con el tradicional ORDER BY col ASC
.
Además, el catálogo estándar no menciona nada interesante acerca de funciones/operadores de comparación extraños. Puede obtener una lista de ellos:
> 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);
Usted se dará cuenta, que no son en su mayoría <
y >
funciones para los tipos primitivos como integer
, date
etc y algunos más para matrices y vectores y así sucesivamente. Ninguno de estos operadores lo ayudará a obtener un pedido personalizado.
En la mayoría de los casos donde se requiere orden personalizado que puede salirse de usar algo como ... ORDER BY somefunc(tablecolumn) ...
donde somefunc
mapea los valores de manera apropiada. Como eso funciona con todas las bases de datos, esta es también la forma más común. Para cosas simples, puede incluso escribir una expresión en lugar de una función personalizada.
engranajes de conmutación de hasta
ORDER BY ... USING
tiene sentido en varios casos:
- el orden es tan poco común, que la
somefunc
truco no funciona.
- Trabajas con un tipo no primitivo (como
point
, circle
o números imaginarios) y no quieres repetir tus consultas con cálculos extraños.
- El conjunto de datos que desea ordenar es tan grande, que se desea o incluso se requiere la ayuda de un índice.
Me centraré en los tipos de datos complejos: a menudo hay más de una forma de ordenarlos de una manera razonable.Un buen ejemplo es point
: Puede "orden" de ellos por la distancia a (0,0), o por x primero, y luego por y o simplemente por y o cualquier otra cosa que desee.
Por supuesto, PostgreSQL tiene operadores predefinidos para point
:
> CREATE TABLE p (p point);
> SELECT p <-> point(0,0) FROM p;
Pero ninguno de ellos se declara utilizable para ORDER BY
por defecto (véase más arriba):
> 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.
operadores simples para point
son los operadores "debajo" y "arriba" <^
y >^
. Comparan simplemente la parte y
del punto. Pero:
> 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.
ORDER BY USING
requiere un operador con semántica definida: Es evidente que debe ser un operador binario, debe aceptar el mismo tipo como argumentos y debe devolver booleano. Creo que también debe ser transitivo (si es < by < c entonces < c). Puede haber más requisitos. Pero todos estos requisitos también son necesarios para btree -index ordering. Esto explica los extraños mensajes de error que contienen la referencia a btree.
ORDER BY USING
también requiere no sólo un operador por definir, pero una clase de operador y una familia operador. Mientras que uno podría implementar la clasificación con un solo operador, PostgreSQL intenta ordenar de manera eficiente y minimizar las comparaciones. Por lo tanto, se utilizan varios operadores incluso cuando especifica solo uno: los demás deben cumplir ciertas restricciones matemáticas. Ya he mencionado la transitividad, pero hay más.
engranajes de conmutación de hasta
vamos a definir algo adecuado: Un operador de puntos que compara sólo la parte y
.
El primer paso es crear una familia de operadores personalizada que se pueda usar con el método de acceso de índice btree. see
> CREATE OPERATOR FAMILY xyzfam USING btree; -- superuser access required!
CREATE OPERATOR FAMILY
siguiente que debe proporcionar una función de comparador que devuelve -1, 0, +1 cuando se comparan dos puntos. Esta función se llamará internamente!
> CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int
AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql;
CREATE FUNCTION
A continuación definimos la clase de operador para la familia. See the manual para una explicación de los números.
> 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
Este paso combina varios operadores y funciones y también define su relación y significado. Por ejemplo, OPERATOR 1
significa: Este es el operador para las pruebas less-than
.
Ahora los operadores <^
y '> ^' se pueden utilizar en 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 - ordenado por y.
Resumiendo:ORDER BY ... USING
es un aspecto interesante bajo el capó de PostgreSQL. Pero nada de lo que necesitará en cualquier momento a menos que trabaje en muy áreas específicas de la tecnología de base de datos.
Otro ejemplo se puede encontrar in the Postgres docs. con código fuente para el ejemplo here y here. Este ejemplo también muestra cómo crear los operadores.
¿Qué quiere decir por "orden de cambio"? –