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 :(得分: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 = '{}')
;
仅建议小改进:
子查询代替CTE,性能稍好一些。
空数组的简化测试:检查文字'{}'
而不是函数调用。
展开数组的子查询级别少一个。
结果:
a | b
--+---
2 | 3
7 | 4
1 | 4
5 | 1
对于随意读者:包装整数的多维数组是必要的,因为Postgres要求(引用错误信息):
多维数组必须具有匹配维度的数组表达式
备用路线将使用 2维文本数组,并使用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
而不是横向交叉连接。