Clo*_*eto 5 arrays postgresql parameter-passing postgresql-9.3
Web 应用程序可以向函数发送array of arrays类似的信息
[
[
[1,2],
[3,4]
],
[
[],
[4,5,6]
]
]
Run Code Online (Sandbox Code Playgroud)
外部数组长度为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
Run Code Online (Sandbox Code Playgroud)
但我想这样我可以做得更好
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
Run Code Online (Sandbox Code Playgroud)
请注意,atext array被传递,然后在函数内部“强制转换”。这是必要的,因为 Postgresql 只能处理尺寸匹配的数组,并且传递的内部数组的尺寸可能不同。我可以在通过之前通过添加一些特殊值(例如零)来“修复”它们,以使它们与最长的长度相同,但我认为在函数内部处理它会更干净。
我错过了什么吗?这是最好的方法吗?
我喜欢你的第二种方法。
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 = '{}')
;
Run Code Online (Sandbox Code Playgroud)
仅建议较小的改进:
使用子查询代替 CTE 可以获得稍微更好的性能。
空数组的简化测试:检查文字'{}'而不是函数调用。
用于展开数组的子查询级别少了一层。
结果:
a | b
--+---
2 | 3
7 | 4
1 | 4
5 | 1
Run Code Online (Sandbox Code Playgroud)
对于普通读者:包装多维整数数组是必要的,因为 Postgres 要求(引用错误消息):
多维数组必须具有维度匹配的数组表达式
另一种路线是使用二维文本数组并使用以下方法取消嵌套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 = '{}');
Run Code Online (Sandbox Code Playgroud)
可能会更快,你能测试一下吗?
在 9.3 之前的版本中,人们将使用显式交叉连接CROSS JOIN而不是横向交叉连接。
| 归档时间: |
|
| 查看次数: |
4912 次 |
| 最近记录: |