2011-07-01 40 views
2

假設我有兩個數組字段在表中,如下所示:將PostgreSQL中的兩個數組合併爲索引和值?

Column | Type | 
--------+-----------+ 
index | integer[] | 
value | integer[] | 

在哪裏都索引和值在長度上相等,並且在「索引」的值被保證是唯一的,例如:

SELECT * FROM ArrayTest; 
    index | value    
-----------+----------------------------------- 
{1,3,5,6} | {100, 103, 105, 106} 

如何做一個查詢返回一個新的數組,其中'index'中的值用作數組索引,'value'中的值成爲與給定索引相關的值,即:

SELECT some_array_function(index, value) as newarray; 
      new_array 
-------------------------------- 
{100, NULL, 103, NULL, 105, 106} 

我想實現的是和PHP中的array_combine一樣。

+2

這可以在PLPGSQL將可能完成。但是這種味道真的很糟糕(即糟糕的設計)你確定你需要在你的數據庫中做這樣一個令人費解的事情嗎? (順便說一句,只有當索引是整數時,才與'array_combine'相同) – leonbloy

+0

我同意它有異味。這有點拼命嘗試優化讀取式應用程序。新陣列將存儲在物化視圖中,僅用於對數據進行某些分析,我認爲這種設計可能會改善目前的情況。 – simonfi

+0

我有一個依賴於數組的功能的項目。 Postgres中只有很少的數組操作函數可用。我驚訝地發現,在一種情況下,使用PL/Python函數比等效的SQL更容易和更快。 –

回答

3

雖然整體是一個壞主意來存儲這樣的數據,做一個方式,它是使用UNNEST函數和過程在客戶端的結果:

SELECT unnest(index), unnest(value) FROM ArrayTest; 

unnest | unnest 
--------+-------- 
     1 | 100 
     3 | 103 
     5 | 105 
     6 | 106 

如果你必須有一個函數來創建一個新的數組這裏是一個總之功能,將做到這一點:

CREATE FUNCTION array_stitch(index_array integer[], value_array integer[]) RETURNS integer[] 
    LANGUAGE plpgsql IMMUTABLE 
    AS $$ 
DECLARE 
    ptr INTEGER; 
    new_array INTEGER[]; 
BEGIN 
    FOR ptr IN 1..array_upper(index_array,1) LOOP 
      new_array[index_array[ptr]] := value_array[ptr]; 
    END LOOP; 

    RETURN new_array; 
END; 
$$; 

編輯:這裏是另一種方式來做到這一點:

SELECT array_agg(val order by idx) as output_array 
FROM (SELECT generate_series(1,idx[array_upper(idx,1)]) from array_test) as g(idx) 
LEFT JOIN (SELECT unnest(idx) as idx, unnest(val) as val FROM array_test\ 
    ) as data_points USING (idx); 
+0

謝謝!第二種方法正是我所期待的。 – simonfi

1

試試這個簡單的程序:

CREATE OR REPLACE FUNCTION merge_arrays(index INTEGER[], value INTEGER[]) RETURNS INTEGER[] AS $$ 
DECLARE 
    arr_size INTEGER; 
    max_index INTEGER; 
    result INTEGER[]; 
    i INTEGER; 
    index_pos INTEGER := 1; 
BEGIN 
    arr_size := array_upper(index, 1); 
    max_index := index[arr_size]; 

    FOR i IN 1..max_index LOOP 
     IF index @> ARRAY[i] THEN 
      result := result || value[index_pos]; 
      index_pos := index_pos + 1; 
     ELSE 
      result := result || '{NULL}'::INTEGER[]; 
     END IF; 

    END LOOP; 

    RETURN result; 
END; 
$$ LANGUAGE PLPGSQL; 

用法:

SELECT merge_arrays(index ,value) from array_test; 
相關問題