如何正确取消嵌套两个数组
How to properly unnest two arrays
我有两个数组:函数中的 foo_array text[]、bar_array text[]。
它们每个都包含字符串,这些字符串将使用 'string_to_array' 函数拆分为数组元素并将类型转换为 bigint。
我想 return table(out1 bigint, out2 bigint) 中的那些数组。
例如,foo_array 和 bar_array 各包含 10 个元素,我希望函数 return 包含这些元素的 10 行。
我只能产生20个元素的输出,并没有真正理解它。
CREATE OR REPLACE FUNCTION ___two_unnests()
RETURNS TABLE(out1 bigint, out2 bigint) AS $$
DECLARE
foo_array text[];
bar_array text[];
foo1 text := array_to_string(ARRAY[1, 2, 3, 4, 5], ',');
foo2 text := array_to_string(ARRAY[11, 22, 33, 44, 55], ',');
bar1 text := array_to_string(ARRAY[6, 7, 8, 9, 10], ',');
bar2 text := array_to_string(ARRAY[66, 77, 88, 99, 1010], ',');
BEGIN
foo_array := (SELECT foo_array || foo1 || foo2);
bar_array := (SELECT bar_array || bar1 || bar2);
RAISE NOTICE 'foo_array: %', foo_array;
RAISE NOTICE 'bar_array: %', bar_array;
RETURN QUERY
SELECT
unnest(string_to_array(foo, ',')::bigint[]),
unnest(string_to_array(bar, ',')::bigint[])
FROM
unnest(foo_array) as foo,
unnest(bar_array) as bar;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM ___two_unnests();
函数的实际输出。
out1 | out2
-----+-----
1 | 6
2 | 7
3 | 8
4 | 9
5 | 10
1 | 11
2 | 22
3 | 33
4 | 44
5 | 55
11 | 6
22 | 7
33 | 8
44 | 9
55 | 10
11 | 11
22 | 22
33 | 33
44 | 44
55 | 55
我想要的输出:
out1 | out2
-----+-----
1 | 6
2 | 7
3 | 8
4 | 9
5 | 10
11 | 66
22 | 77
33 | 88
44 | 99
55 | 1010
解决方案使用建议
CREATE OR REPLACE FUNCTION ___two_unnests() RETURNS TABLE(out1 bigint, out2 bigint) AS $$
DECLARE
foo_array text[];
bar_array text[];
foo_slice text;
foo_text text := '';
foo_firstiter boolean := true;
bar_slice text;
bar_text text := '';
bar_firstiter boolean := true;
out1_array bigint[];
out2_array bigint[];
foo1 text := array_to_string(ARRAY[1, 2, 3, 4, 5], ',');
foo2 text := array_to_string(ARRAY[11, 22, 33, 44, 55], ',');
bar1 text := array_to_string(ARRAY[6, 7, 8, 9, 10], ',');
bar2 text := array_to_string(ARRAY[66, 77, 88, 99, 1010], ',');
BEGIN
foo_array := (SELECT foo_array || foo1 || foo2);
bar_array := (SELECT bar_array || bar1 || bar2);
RAISE NOTICE 'foo_array: %', foo_array;
RAISE NOTICE 'bar_array: %', bar_array;
FOREACH foo_slice IN ARRAY foo_array LOOP
IF foo_firstiter = true THEN
foo_text := foo_text || foo_slice;
foo_firstiter := false;
ELSE
foo_text := foo_text || ',' || foo_slice;
END IF;
END LOOP;
FOREACH bar_slice IN ARRAY bar_array LOOP
IF bar_firstiter = true THEN
bar_text := bar_text || bar_slice;
bar_firstiter := false;
ELSE
bar_text := bar_text || ',' || bar_slice;
END IF;
END LOOP;
out1_array := (SELECT string_to_array(foo_text, ',')::bigint[]);
out2_array := (SELECT string_to_array(bar_text, ',')::bigint[]);
RAISE NOTICE 'out1_array: %', out1_array;
RAISE NOTICE 'out2_array: %', out2_array;
RETURN QUERY SELECT un1.val::bigint,
un2.val::bigint
FROM unnest(out1_array) WITH ORDINALITY un1 (val, ord)
FULL JOIN unnest(out2_array) WITH ORDINALITY un2 (val, ord)
ON un2.ord = un1.ord;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM ___two_unnests();
你可以unnest()
WITH ORDINALITY
,让每个元素都有一个索引,并在上面全连接结果。
SELECT un1.val::bigint,
un2.val::bigint
FROM unnest(ARRAY[1, 2, 3, 4, 5, 11, 22, 33, 44, 55]) WITH ORDINALITY un1 (val, ord)
FULL JOIN unnest(ARRAY[6, 7, 8, 9, 10, 66, 77, 88, 99, 1010]) WITH ORDINALITY un2 (val, ord)
ON un2.ord = un1.ord;
如果你有现代 PostgreSQL,你可以使用多列 unnest
函数
SELECT * FROM unnest(ARRAY[1, 2, 3, 4, 5] || ARRAY[11, 22, 33, 44, 55],
ARRAY[6, 7, 8, 9, 10] || ARRAY[66, 77, 88, 99, 1010]);
┌────────┬────────┐
│ unnest │ unnest │
╞════════╪════════╡
│ 1 │ 6 │
│ 2 │ 7 │
│ 3 │ 8 │
│ 4 │ 9 │
│ 5 │ 10 │
│ 11 │ 66 │
│ 22 │ 77 │
│ 33 │ 88 │
│ 44 │ 99 │
│ 55 │ 1010 │
└────────┴────────┘
不要使用子查询来代替表达式
不好(代码可读性差,速度慢)
var := (SELECT a || b || c); -- don't do this!
改为
var := a || b || c;
我有两个数组:函数中的 foo_array text[]、bar_array text[]。 它们每个都包含字符串,这些字符串将使用 'string_to_array' 函数拆分为数组元素并将类型转换为 bigint。
我想 return table(out1 bigint, out2 bigint) 中的那些数组。
例如,foo_array 和 bar_array 各包含 10 个元素,我希望函数 return 包含这些元素的 10 行。 我只能产生20个元素的输出,并没有真正理解它。
CREATE OR REPLACE FUNCTION ___two_unnests()
RETURNS TABLE(out1 bigint, out2 bigint) AS $$
DECLARE
foo_array text[];
bar_array text[];
foo1 text := array_to_string(ARRAY[1, 2, 3, 4, 5], ',');
foo2 text := array_to_string(ARRAY[11, 22, 33, 44, 55], ',');
bar1 text := array_to_string(ARRAY[6, 7, 8, 9, 10], ',');
bar2 text := array_to_string(ARRAY[66, 77, 88, 99, 1010], ',');
BEGIN
foo_array := (SELECT foo_array || foo1 || foo2);
bar_array := (SELECT bar_array || bar1 || bar2);
RAISE NOTICE 'foo_array: %', foo_array;
RAISE NOTICE 'bar_array: %', bar_array;
RETURN QUERY
SELECT
unnest(string_to_array(foo, ',')::bigint[]),
unnest(string_to_array(bar, ',')::bigint[])
FROM
unnest(foo_array) as foo,
unnest(bar_array) as bar;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM ___two_unnests();
函数的实际输出。
out1 | out2
-----+-----
1 | 6
2 | 7
3 | 8
4 | 9
5 | 10
1 | 11
2 | 22
3 | 33
4 | 44
5 | 55
11 | 6
22 | 7
33 | 8
44 | 9
55 | 10
11 | 11
22 | 22
33 | 33
44 | 44
55 | 55
我想要的输出:
out1 | out2
-----+-----
1 | 6
2 | 7
3 | 8
4 | 9
5 | 10
11 | 66
22 | 77
33 | 88
44 | 99
55 | 1010
解决方案使用
CREATE OR REPLACE FUNCTION ___two_unnests() RETURNS TABLE(out1 bigint, out2 bigint) AS $$
DECLARE
foo_array text[];
bar_array text[];
foo_slice text;
foo_text text := '';
foo_firstiter boolean := true;
bar_slice text;
bar_text text := '';
bar_firstiter boolean := true;
out1_array bigint[];
out2_array bigint[];
foo1 text := array_to_string(ARRAY[1, 2, 3, 4, 5], ',');
foo2 text := array_to_string(ARRAY[11, 22, 33, 44, 55], ',');
bar1 text := array_to_string(ARRAY[6, 7, 8, 9, 10], ',');
bar2 text := array_to_string(ARRAY[66, 77, 88, 99, 1010], ',');
BEGIN
foo_array := (SELECT foo_array || foo1 || foo2);
bar_array := (SELECT bar_array || bar1 || bar2);
RAISE NOTICE 'foo_array: %', foo_array;
RAISE NOTICE 'bar_array: %', bar_array;
FOREACH foo_slice IN ARRAY foo_array LOOP
IF foo_firstiter = true THEN
foo_text := foo_text || foo_slice;
foo_firstiter := false;
ELSE
foo_text := foo_text || ',' || foo_slice;
END IF;
END LOOP;
FOREACH bar_slice IN ARRAY bar_array LOOP
IF bar_firstiter = true THEN
bar_text := bar_text || bar_slice;
bar_firstiter := false;
ELSE
bar_text := bar_text || ',' || bar_slice;
END IF;
END LOOP;
out1_array := (SELECT string_to_array(foo_text, ',')::bigint[]);
out2_array := (SELECT string_to_array(bar_text, ',')::bigint[]);
RAISE NOTICE 'out1_array: %', out1_array;
RAISE NOTICE 'out2_array: %', out2_array;
RETURN QUERY SELECT un1.val::bigint,
un2.val::bigint
FROM unnest(out1_array) WITH ORDINALITY un1 (val, ord)
FULL JOIN unnest(out2_array) WITH ORDINALITY un2 (val, ord)
ON un2.ord = un1.ord;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM ___two_unnests();
你可以unnest()
WITH ORDINALITY
,让每个元素都有一个索引,并在上面全连接结果。
SELECT un1.val::bigint,
un2.val::bigint
FROM unnest(ARRAY[1, 2, 3, 4, 5, 11, 22, 33, 44, 55]) WITH ORDINALITY un1 (val, ord)
FULL JOIN unnest(ARRAY[6, 7, 8, 9, 10, 66, 77, 88, 99, 1010]) WITH ORDINALITY un2 (val, ord)
ON un2.ord = un1.ord;
如果你有现代 PostgreSQL,你可以使用多列 unnest
函数
SELECT * FROM unnest(ARRAY[1, 2, 3, 4, 5] || ARRAY[11, 22, 33, 44, 55],
ARRAY[6, 7, 8, 9, 10] || ARRAY[66, 77, 88, 99, 1010]);
┌────────┬────────┐
│ unnest │ unnest │
╞════════╪════════╡
│ 1 │ 6 │
│ 2 │ 7 │
│ 3 │ 8 │
│ 4 │ 9 │
│ 5 │ 10 │
│ 11 │ 66 │
│ 22 │ 77 │
│ 33 │ 88 │
│ 44 │ 99 │
│ 55 │ 1010 │
└────────┴────────┘
不要使用子查询来代替表达式
不好(代码可读性差,速度慢)
var := (SELECT a || b || c); -- don't do this!
改为
var := a || b || c;