Um exemplo bem simples seria:
> SELECT * FROM tab ORDER BY col USING <
Mas isso é chato, porque isso não é nada que você não consiga com o tradicional
ORDER BY col ASC
. Além disso, o catálogo padrão não menciona nada empolgante sobre funções/operadores de comparação estranhos. Você pode obter uma lista deles:
> 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);
Você notará que existem principalmente
<
e >
funções para tipos primitivos como integer
, date
etc e mais alguns para matrizes e vetores e assim por diante. Nenhum desses operadores o ajudará a obter um pedido personalizado. Na maioria casos em que a ordenação personalizada é necessária, você pode usar algo como
... ORDER BY somefunc(tablecolumn) ...
onde somefunc
mapeia os valores adequadamente. Como isso funciona com todos os bancos de dados, essa também é a maneira mais comum. Para coisas simples, você pode até escrever uma expressão em vez de uma função personalizada. Mudando de marcha
ORDER BY ... USING
faz sentido em vários casos:- A ordenação é tão incomum que o
somefunc
truque não funciona. - Você trabalha com um tipo não primitivo (como
point
,circle
ou números imaginários) e você não quer se repetir em suas consultas com cálculos estranhos. - O conjunto de dados que você deseja classificar é tão grande que o suporte por um índice é desejado ou até mesmo necessário.
Vou me concentrar nos tipos de dados complexos:geralmente há mais de uma maneira de classificá-los de maneira razoável. Um bom exemplo é
point
:Você pode "ordená-los" pela distância até (0,0) ou por x primeiro, depois por y ou apenas por y ou qualquer outra coisa que você queira. É claro que o PostgreSQL tem operadores predefinidos para
point
: > CREATE TABLE p ( p point );
> SELECT p <-> point(0,0) FROM p;
Mas nenhuma deles é declarado utilizável para
ORDER BY
por padrão (veja acima): > 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
são os operadores "abaixo" e "acima" <^
e >^
. Eles comparam simplesmente o y
parte do ponto. Mas: > 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
requer um operador com semântica definida:Obviamente deve ser um operador binário, deve aceitar o mesmo tipo de argumentos e deve retornar booleano. Eu acho que também deve ser transitivo (se a btree adequado -ordenação de índice. Isso explica as estranhas mensagens de erro contendo a referência a btree . ORDER BY USING
também requer não apenas um operador a ser definido, mas uma classe de operador e uma família de operadores . Enquanto um poderia implementar a ordenação com apenas um operador, o PostgreSQL tenta ordenar de forma eficiente e minimizar as comparações. Portanto, vários operadores são usados mesmo quando você especifica apenas um - os outros devem seguir certas restrições matemáticas - já mencionei transitividade, mas há mais. Mudando de marcha
Vamos definir algo adequado:Um operador para pontos que compara apenas o
y
papel. O primeiro passo é criar uma família de operadores personalizada que pode ser usada pela btree método de acesso ao índice. Vejo
> CREATE OPERATOR FAMILY xyzfam USING btree; -- superuser access required!
CREATE OPERATOR FAMILY
Em seguida, devemos fornecer uma função de comparação que retorna -1, 0, +1 ao comparar dois pontos. Esta função VOCÊ ser chamado 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
Em seguida, definimos a classe de operadores para a família. Consulte o manual para obter uma explicação dos 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
Esta etapa combina vários operadores e funções e também define sua relação e significado. Por exemplo
OPERATOR 1
significa:Este é o operador para less-than
testes. Agora os operadores
<^
e >^
pode ser usado em 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 .
Resumindo:
ORDER BY ... USING
é uma visão interessante sob o capô do PostgreSQL. Mas nada que você vai precisar tão cedo, a menos que você trabalhe em muito áreas específicas da tecnologia de banco de dados. Outro exemplo pode ser encontrado nos documentos do Postgres. com código-fonte para o exemplo aqui e aqui. Este exemplo também mostra como criar os operadores.