如何正确解除两个数组的嵌套

Off*_*ics 1 postgresql plpgsql

我有两个数组:函数内的 foo_array text[]、bar_array text[] 。它们每个都包含字符串,这些字符串将使用“string_to_array”函数拆分为数组元素,并将类型转换为 bigint。

我想在表中返回这些数组(out1 bigint,out2 bigint)。

例如,foo_array 和 bar_array 每个包含 10 个元素,我希望该函数返回包含这些元素的 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();
Run Code Online (Sandbox Code Playgroud)

函数的实际输出。

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
Run Code Online (Sandbox Code Playgroud)

我想要的输出:

out1 |  out2
-----+-----
1    |  6
2    |  7
3    |  8
4    |  9
5    |  10
11   |  66
22   |  77
33   |  88
44   |  99
55   |  1010
Run Code Online (Sandbox Code Playgroud)

解决方案使用sticky-bit的建议

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();
Run Code Online (Sandbox Code Playgroud)

Pav*_*ule 6

如果你有一个现代的 PostgreSQL,你可以使用多列unnest函数

\n\n
SELECT * FROM unnest(ARRAY[1, 2, 3, 4, 5] || ARRAY[11, 22, 33, 44, 55],\n                     ARRAY[6, 7, 8, 9, 10] || ARRAY[66, 77, 88, 99, 1010]);\n\n\xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x82 unnest \xe2\x94\x82 unnest \xe2\x94\x82\n\xe2\x95\x9e\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xaa\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa1\n\xe2\x94\x82      1 \xe2\x94\x82      6 \xe2\x94\x82\n\xe2\x94\x82      2 \xe2\x94\x82      7 \xe2\x94\x82\n\xe2\x94\x82      3 \xe2\x94\x82      8 \xe2\x94\x82\n\xe2\x94\x82      4 \xe2\x94\x82      9 \xe2\x94\x82\n\xe2\x94\x82      5 \xe2\x94\x82     10 \xe2\x94\x82\n\xe2\x94\x82     11 \xe2\x94\x82     66 \xe2\x94\x82\n\xe2\x94\x82     22 \xe2\x94\x82     77 \xe2\x94\x82\n\xe2\x94\x82     33 \xe2\x94\x82     88 \xe2\x94\x82\n\xe2\x94\x82     44 \xe2\x94\x82     99 \xe2\x94\x82\n\xe2\x94\x82     55 \xe2\x94\x82   1010 \xe2\x94\x82\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n\n

不要使用子选择代替表达式

\n\n

很糟糕(代码可读性较差且速度较慢)

\n\n
var := (SELECT a || b || c); -- don't do this!\n
Run Code Online (Sandbox Code Playgroud)\n\n

反而

\n\n
var := a || b || c;\n
Run Code Online (Sandbox Code Playgroud)\n