PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Criando operador de igualdade personalizado para o tipo PostgreSQL (ponto) para chamadas DISTINCT


Para selecionar valores distintos, o Postgres deve ter a capacidade de classificar a coluna. Você precisa criar uma btree completa classe de operador para ponto de tipo, ou seja, cinco operadores (< , <= , = , >= , > ) e uma função comparando dois pontos e retornando inteiro, conforme descrito no the documentação .

Para o operador = você pode usar a função existente point_eq(point, point) :
create operator = (leftarg = point, rightarg = point, procedure = point_eq, commutator = =);

Exemplo de definição do operador < :
create function point_lt(point, point)
returns boolean language sql immutable as $$
    select $1[0] < $2[0] or $1[0] = $2[0] and $1[1] < $2[1]
$$;

create operator < (leftarg = point, rightarg = point, procedure = point_lt, commutator = >);

Defina os operadores <= , => e > de maneira semelhante. Tendo todos os cinco operadores, crie uma função:
create function btpointcmp(point, point)
returns integer language sql immutable as $$
    select case 
        when $1 = $2 then 0
        when $1 < $2 then -1
        else 1
    end
$$;

E finalmente:
create operator class point_ops
    default for type point using btree as
        operator 1 <,
        operator 2 <=,
        operator 3 =,
        operator 4 >=,
        operator 5 >,
        function 1 btpointcmp(point, point);

Com a classe point_ops definido, você pode selecionar valores de pontos distintos e ordenar as linhas pela coluna do tipo de ponto, por exemplo:
with q(p) as (
    values 
        ('(1,1)'::point),
        ('(1,2)'::point),
        ('(2,1)'::point),
        ('(1,1)'::point))
select distinct *
from q
order by 1 desc;

   p   
-------
 (2,1)
 (1,2)
 (1,1)
(3 rows)    

Você também pode criar um índice (único) em uma coluna de ponto.

Atualizar.

Postgres tem mais de 2800 funções auxiliares que suportam operadores, índices, funções padrão, etc. Você pode listá-los consultando pg_proc , por exemplo.:
select format('%s(%s)', proname, pg_get_function_arguments(oid))
from pg_proc
where pronamespace::regnamespace = 'pg_catalog'
and proname like 'point%'

A função point_eq(point, point) é usado na implementação de algumas funções e operadores geométricos.