2012-10-13 34 views
11

我有一個表4個陣列列的順序..結果是這樣的:比較是否相等陣列,忽略元件

ids  signed_ids new_ids new_ids_signed 
{1,2,3} | {2,1,3} | {4,5,6} | {6,5,4} 

反正比較idssigned_ids使得它們出來相等,通過忽略元素的順序?

+1

這些陣列是不相等的。我猜對了,你真正的問題是「如何比較兩個PostgreSQL數組,就好像它們是集合一樣,即不考慮順序?」 –

+0

是的,這正是我要求的:) – user766987

+0

爲了反映意圖而編輯的問題。 –

回答

9

最簡單的事情就是對它們進行排序並對它們進行排序。見sorting arrays in PostgreSQL

給定的樣本數據:

CREATE TABLE aa(ids integer[], signed_ids integer[]); 
INSERT INTO aa(ids, signed_ids) VALUES (ARRAY[1,2,3], ARRAY[2,1,3]); 

做的最好的事情是,如果數組條目總是整數是使用intarray擴展,如Erwin explains in his answer。這是一個lot比任何純SQL制定更快。

否則,對於任何數據類型工作的通用版本,定義array_sort(anyarray)

CREATE OR REPLACE FUNCTION array_sort(anyarray) RETURNS anyarray AS $$ 
SELECT array_agg(x order by x) FROM unnest($1) x; 
$$ LANGUAGE 'SQL'; 

,並用它進行排序和比較排序的數組:

SELECT array_sort(ids) = array_sort(signed_ids) FROM aa; 

有一個重要的警告:

SELECT array_sort(ARRAY[1,2,2,4,4]) = array_sort(ARRAY[1,2,4]); 

將是錯誤的。這可能是也可能不是你想要的,取決於你的意圖。


或者,定義一個函數array_compare_as_set

CREATE OR REPLACE FUNCTION array_compare_as_set(anyarray,anyarray) RETURNS boolean AS $$ 
SELECT CASE 
    WHEN array_dims($1) <> array_dims($2) THEN 
    'f' 
    WHEN array_length($1,1) <> array_length($2,1) THEN 
    'f' 
    ELSE 
    NOT EXISTS (
     SELECT 1 
     FROM unnest($1) a 
     FULL JOIN unnest($2) b ON (a=b) 
     WHERE a IS NULL or b IS NULL 
    ) 
    END 
$$ LANGUAGE 'SQL' IMMUTABLE; 

然後:

SELECT array_compare_as_set(ids, signed_ids) FROM aa; 

這是來自比較兩個array_sort ED值微妙的不同。 array_compare_as_set將消除重複項,使得array_compare_as_set(ARRAY[1,2,3,3],ARRAY[1,2,3])爲真,而array_sort(ARRAY[1,2,3,3]) = array_sort(ARRAY[1,2,3])將爲假。

這兩種方法都會有很差的表現。考慮確保您始終將您的數組存儲在首位。

+0

爲你的餐桌添加一個別名,精彩!謝謝:) – user766987

+0

@ user766987更新了更好的定義 –

+0

@ user766987 ...並用不同的方法再次更新,只是爲了好玩。 –

12

處理數組整數您可以安裝擴展intarray

與(從Postgres 9.1或更高版本)每個數據庫安裝一次:

CREATE EXTENSION intarray; 

那麼你可以:

SELECT uniq(sort(ids)) = uniq(sort(signed_ids));

或者:

SELECT ids @> signed_ids AND ids <@ signed_ids;

粗體強調功能和來自intarray的運營商。 這兩個表達式都將忽略元素的順序和重複性。更多關於這些功能和操作的幫助手冊here

注:

  • intarray運營商只爲integer,不bigintsmallint或任何其他數據類型陣列的工作。
  • 由於標準Postgres發行版中存在數組類型的通用變體,因此您可以使用遏制運算符@><@而不安裝intarrayintarray只爲int[]安裝專門的操作員,通常速度更快。
  • 與泛型操作符不同,intarray不接受數組中的NULL值,這可能會造成混淆:現在,如果在任何涉及的數組中都有NULL,則會收到錯誤消息。
    如果需要使用NULL值的工作,你可以默認爲標準,一般運營商通過架構進行資格與OPERATOR構建運營商:

    SELECT ARRAY[1,4,null,3]::int[] OPERATOR([email protected]>) ARRAY[3,1]::int[]
  • 通用運營商不能使用索引與一個intarray操作符類,反之亦然。

+0

'intarray'是否也適用於'bigint'陣列? – ma11hew28

+0

第一個解決方案(使用'sort')比第二個解決方案(使用'@>'和'<@')更快嗎?如果沒有,我想我可以不用'intarray'。 – ma11hew28

+1

@mattdipasquale:我增加了一些解釋。 –

6

您可以使用包含在由操作者:

(ARRAY1 < @數組2和ARRAY1 @>數組2)