“创建自定义”;相等运算符“;对于不同调用的PostgreSQL类型(点)

“创建自定义”;相等运算符“;对于不同调用的PostgreSQL类型(点),postgresql,types,operator-overloading,distinct,Postgresql,Types,Operator Overloading,Distinct,在我的一个表中,有一列定义为PostgreSQL类型。我专门将其用于模块,距离操作符。(是的,我知道PostGIS,但它比我的需要复杂得多,我只需要给一个带有lat/long对的表,按距离订购表,并在提供的lat/long中留有误差。) 但是,点似乎没有实现相等,因此对表的任何DISTINCT调用,如SELECT DISTINCT*FROM mytable会导致以下错误: ERROR: could not identify an equality operator for type point

在我的一个表中,有一列定义为PostgreSQL类型。我专门将其用于模块,
距离操作符。(是的,我知道PostGIS,但它比我的需要复杂得多,我只需要给一个带有lat/long对的表,按距离订购表,并在提供的lat/long中留有误差。)

但是,
似乎没有实现相等,因此对表的任何
DISTINCT
调用,如
SELECT DISTINCT*FROM mytable
会导致以下错误:

ERROR: could not identify an equality operator for type point
虽然通常不建议修补内置类型,但我不介意在这种情况下这样做,我尝试为
点创建自己的
=
操作符:

CREATE OR REPLACE FUNCTION compare_points_equality(point1 POINT, point2 POINT)
  RETURNS BOOLEAN AS $$
  SELECT point1[0] = point2[0] AND point1[1] = point1[1];
$$ LANGUAGE SQL IMMUTABLE;

CREATE OPERATOR = (
  LEFTARG = POINT,
  RIGHTARG = POINT,
  PROCEDURE = compare_points_equality,
  COMMUTATOR = =,
  NEGATOR = !=,
  HASHES,
  MERGES
);
create operator = (leftarg = point, rightarg = point, procedure = point_eq, commutator = =);

但即使创建了这个,我也会得到同样的错误。如果不创建
=
,我应该如何创建“相等运算符”?

要选择不同的值,Postgres必须能够对列进行排序。 您需要为类型点创建一个完整的btree,即五个运算符(
)和一个比较两个点并返回整数的函数,如中所述

对于操作员
=
,您可以使用现有功能
点(点,点)


操作符
的示例定义很遗憾,我不能使用这个答案,因为我没有超级用户访问数据库的权限,显然这是创建操作符类所必需的。不知道为什么。是的,如中所述:目前,创建用户必须是超级用户。(做出此限制是因为错误的运算符类定义可能会混淆甚至使服务器崩溃。)末尾的>是否正确创建运算符<(leftarg=point,rightarg=point,procedure=point_lt,Converator=>);或者应该是“胡安迪戈”——这是正确的。如果存在换向器运算符,则应标识换向器运算符,以便Postgres可以根据需要反转操作数的顺序。参见操作员的
=您可以使用现有的功能点(点,点):
从哪里来
点\u eq
?为什么它已经存在?
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 = >);
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
$$;
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);
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)    
select format('%s(%s)', proname, pg_get_function_arguments(oid))
from pg_proc
where pronamespace::regnamespace = 'pg_catalog'
and proname like 'point%'