2013-10-09 112 views
3

Web應用程序可以發送到的功能的array of arrays傳遞數組作爲參數的數組的函數

[ 
    [ 
     [1,2], 
     [3,4] 
    ], 
    [ 
     [], 
     [4,5,6] 
    ] 
] 

外陣列長度是n > 0。中間數組的長度是恆定的,在這個例子中是2。內部陣列長度爲n >= 0

我可以串建立這樣的:

with t(a, b) as (
    values (1, 4), (2, 3), (1, 4), (7, 3), (7, 4) 
) 
select distinct a, b 
from t 
where 
    (a = any(array[1,2]) or array_length(array[1,2],1) is null) 
    and 
    (b = any(array[3,4]) or array_length(array[3,4],1) is null) 
    or 
    (a = any(array[]::int[]) or array_length(array[]::int[],1) is null) 
    and 
    (b = any(array[4,5,6]) or array_length(array[4,5,6],1) is null) 
; 
a | b 
---+--- 
7 | 4 
1 | 4 
2 | 3 

但我認爲我可以做的更好這樣

with t(a, b) as (
    values (1, 4), (2, 3), (1, 4), (7, 3), (7, 4) 
), u as (
    select unnest(a)::text[] as a 
    from (values 
     (
      array[ 
       '{"{1,2}", "{3,4}"}', 
       '{"{}", "{4,5,6}"}' 
      ]::text[] 
     ) 
    ) s(a) 
), s as (
    select a[1]::int[] as a1, a[2]::int[] as a2 
    from u 
) 
select distinct a, b 
from 
    t 
    inner join 
    s on 
     (a = any(a1) or array_length(a1, 1) is null) 
     and 
     (b = any(a2) or array_length(a2, 1) is null) 
; 
a | b 
---+--- 
7 | 4 
2 | 3 
1 | 4 

注意到一個text array傳遞,然後「鑄造」裏面的功能。這是必要的,因爲Postgresql只能處理匹配維度的數組,並且傳遞的內部數組可以在維度上變化。在傳遞之前,我可以通過添加一些特殊的值(如零)來「修復」它們,使其長度與最長的一樣長,但我認爲在函數內部處理它更清晰。

我錯過了什麼嗎?這是最好的方法嗎?

+0

是以給定的文本格式包裹的三維數組的格式,還是您可以選擇如何傳遞這些值?而接收這些值的函數是plpgsql? Postgres版本? –

+0

@Erwin我可以選擇如何傳遞值。前端是Python,非常靈活。這種格式就是我如何管理它的工作。該函數現在在SQL中用於簡化,但可以是plpgsql或plpython。 Postgresql 9.3。 –

回答

1

我喜歡你的第二種方法。

SELECT DISTINCT t.* 
FROM (VALUES (1, 4), (5, 1), (2, 3), (1, 4), (7, 3), (7, 4)) AS t(a, b) 
JOIN (
    SELECT arr[1]::int[] AS a1 
     ,arr[2]::int[] AS b1 
    FROM (
     SELECT unnest(ARRAY['{"{1,2}", "{3,4}"}' 
         ,'{"{}" , "{4,5,6}"}' 
         ,'{"{5}" , "{}"}' -- added element to 1st dimension 
         ])::text[] AS arr  -- 1d text array 
    ) sub 
    ) s ON (a = ANY(a1) OR a1 = '{}') 
     AND (b = ANY(b1) OR b1 = '{}') 
; 

暗示只有輕微的改進:

  1. 子查詢,而不是熱膨脹係數爲表現略好。

  2. 空數組簡化測試:檢查文字'{}'而不是函數調用。

  3. 解開數組的一個子查詢級別。

結果:

a | b 
--+--- 
2 | 3 
7 | 4 
1 | 4 
5 | 1 

對於普通讀者:包裝紙整數的多維數組是必要的,因爲要求的Postgres即(引用的錯誤消息):

多維數組必須具有匹配維度的數組表達式

一種備用路由將與一個2維文本陣列和UNNEST它使用generate_subscripts()

WITH a(arr) AS (SELECT '{{"{1,2}", "{3,4}"} 
         ,{"{}", "{4,5,6}"} 
         ,{"{5}", "{}"}}'::text[] -- 2d text array 
      ) 
SELECT DISTINCT t.* 
FROM (VALUES (1, 4), (5, 1), (2, 3), (1, 4), (7, 3), (7, 4)) AS t(a, b) 
JOIN (
    SELECT arr[i][1]::int[] AS a1 
     ,arr[i][2]::int[] AS b1 
    FROM a, generate_subscripts(a.arr, 1) i  -- using implicit LATERAL 
    ) s ON (t.a = ANY(s.a1) OR s.a1 = '{}') 
     AND (t.b = ANY(s.b1) OR s.b1 = '{}'); 

可能更快,可以測試?

在9.3之前的版本中,將使用明確的CROSS JOIN而不是橫向交叉連接。

+1

是的'generate_subscripts'版本在實際功能中一直更快。執行時間從10到5毫秒。 –