2016-01-24 22 views
1

在我的一個表中,我有一個定義爲PostgreSQL類型的列point。我用這個爲earthdistance模塊—特別是<@>距離運算符。 (是的,我知道PostGIS,但它比我的需求複雜得多,它只是給出了一個帶有經/緯度對的表格,按照提供的緯度/經度對距離進行排序,以獲得誤差。)爲PostgreSQL類型(點)創建DISTINCT調用的自定義「相等運算符」

然而,point似乎已經沒有平等的實現,所以任何DISTINCT呼叫在桌子上像SELECT DISTINCT * FROM mytable導致以下錯誤:

ERROR: could not identify an equality operator for type point 

雖然,我不介意這是一般不妥當的,以內置類型補丁這種情況下這樣做,我試圖創建我自己的=運營商爲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 
); 

但即使創建後,我也會得到相同的錯誤。如果不創建=,我應該如何創建「平等運算符」?

回答

2

要選擇不同的值Postgres必須能夠對列進行排序。 需要創建一個完整的B樹operator class類型點,即5個運算符(<<==>=>)並比較兩個點並返回整數,因爲它是在the documentation描述的功能。

對於運營商=您可以使用現有的功能point_eq(point, point):運營商<

create operator = (leftarg = point, rightarg = point, procedure = point_eq, commutator = =); 

示例定義:

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); 

有了定義,你可以先點的列中選擇不同的點值和訂單行類point_ops,例如:

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)  

您還可以創建(唯一的)指數上的點列。

+0

很遺憾,我無法使用這個答案,因爲我沒有超級用戶訪問數據庫,顯然這是創建一個操作符類所需的。不知道爲什麼。 – jdotjdot

+0

是的,如[文檔](http://www.postgresql.org/docs/current/static/sql-createopclass.html)中所述: *目前,創建用戶必須是超級用戶。 (這個限制是因爲錯誤的操作符類定義可能會混淆甚至導致服務器崩潰。)* – klin

+0

在末尾正確的創建操作符<(leftarg = point,rightarg = point,procedure = point_lt,commutator =>);或者它應該是< –

相關問題