2011-08-26 27 views
33

La cláusula ORDER BY se encuentran descritos en la PostgreSQLdocumentation como:"ORDER BY ... El uso de" cláusula en PostgreSQL

ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] 

alguien puede darme algunos ejemplos de cómo utilizar la USING operator? ¿Es posible obtener un orden alternativo del conjunto de resultados?

+0

¿Qué quiere decir por "orden de cambio"? –

Respuesta

37

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.

+1

+1 ¡Gran respuesta! –

+0

Muy, muy buena explicación, gracias. – LauriK

0

Optionally one can add the key word ASC (ascending) or DESC (descending) after any expression in the ORDER BY clause. If not specified, ASC is assumed by default. Alternatively, a specific ordering operator name can be specified in the USING clause. An ordering operator must be a less-than or greater-than member of some B-tree operator family. ASC is usually equivalent to USING < and DESC is usually equivalent to USING >.

PostgreSQL 9.0

Puede ser algo como esto creo (no tengo postgres para verificar esto en este momento, pero voy a verificar más adelante)

SELECT Name FROM Person 
ORDER BY NameId USING > 
+0

La línea que dejaste también es interesante: '(Pero el creador de un tipo de datos definido por el usuario puede definir exactamente cuál es el ordenamiento por defecto, y podría corresponder a operadores con otros nombres). – Vache

+0

Creo que el OP ya sabe esto; están pidiendo ejemplos de uso – NullUserException

+0

Ya lo leí, pero ¿puedes dar otros ejemplos que no sean "usar <" y "usar>"? – markus

4

Muestras:

CREATE TABLE test 
(
    id serial NOT NULL, 
    "number" integer, 
    CONSTRAINT test_pkey PRIMARY KEY (id) 
) 

insert into test("number") values (1),(2),(3),(0),(-1); 

select * from test order by number USING > //gives 3=>2=>1=>0=>-1 

select * from test order by number USING < //gives -1=>0=>1=>2=>3 

Por lo tanto, es equivalente a desc y . Pero usted puede usar su propio operador, que es la característica esencial de USING

+1

¿Puede darme un ejemplo usando un operador personalizado? – markus

+2

Tengo curiosidad acerca de eso también.Eso suena como una característica bastante ingeniosa de Postgres, hay –

+0

Bueno, el simple 'Crear función op_func ...' => 'Crear operador === (procedure = op_func' =>' ordenar por === 'me tiró' ERROR : operador === no es un operador de pedidos válido LÍNEA 1: seleccione * de orden de prueba por número UTILIZACIÓN === ^ CONSEJO: Los operadores de pedidos deben ser "<" or ">" miembros de familias de operadores btree. No estoy bastante familiarizado con las clases de operadores y las familias, así que todavía no puedo dar con el ejemplo. Lo investigaré, pero no soy un gurú de PostgreSQL en realidad ... – J0HN

1

Buenas respuestas, pero no mencionaron ningún caso valioso para USAR.

Al crear un índice con una familia de operadores no predeterminados, por ejemplo varchar_pattern_ops (~> ~, ~ < ~, ~> = ~ ...) en lugar de <,>,> = ... luego, si busca basado en el índice y desea usar índice en orden por cláusula, debe especificar USING con el operador apropiado.

Esto se puede ilustrar con tal ejemplo:

CREATE INDEX index_words_word ON words(word text_pattern_ops); 

Lets comparar esta dos consultas:

SELECT * FROM words WHERE word LIKE 'o%' LIMIT 10; 

y

SELECT * FROM words WHERE word LIKE 'o%' ORDER BY word LIMIT 10; 

La diferencia entre sus ejecuciones es casi 100 veces en 500,000 palabras DB! Y también es posible que los resultados no sean correctos dentro de la configuración regional que no sea C.

¿Cómo pudo pasar esto?

Al realizar la búsqueda con LIKE y ORDER BY cláusula, usted realmente hacer esta llamada:

SELECT * FROM words WHERE word ~>=~ 'o' AND word ~<~'p' ORDER BY word USING < LIMIT 10; 

Su índice creado con ~ < ~ operador en mente, por lo que PG no puede utilizar el índice dado en una orden dada por cláusula. consulta derecho a hacer las cosas debe ser reescrito a esta forma:

SELECT * FROM words WHERE word ~>=~ 'o' AND word ~<~'p' ORDER BY word USING ~<~ LIMIT 10; 

o

SELECT * FROM words WHERE word LIKE 'o%' ORDER BY word USING ~<~ LIMIT 10; 
Cuestiones relacionadas