March 7th, 2011 by depesz | Tags: , , , , , , | 4 comments »
Did it help? If yes - maybe you can help me?

On 16th of February, Tom Lane committed patch:

Add FOREACH IN ARRAY looping to plpgsql.
 
(I'm not entirely sure that we've finished bikeshedding the syntax details,
but the functionality seems OK.)
 
Pavel Stehule, reviewed by Stephen Frost and Tom Lane

This adds simpler syntax to capability that was already there, but it's easier to write and easier to read, so I think it's a good thing.

When you had previously array variable in PL/pgSQL, you had to either use generate_subscripts, or unnest:

CREATE OR REPLACE FUNCTION test( in_array TEXT[] ) RETURNS void as $$
DECLARE
    i INT4;
    t TEXT;
BEGIN
    FOR i IN SELECT generate_subscripts( in_array, 1 ) LOOP
        raise notice 'i: %', in_array[ i ];
    END loop;
    FOR t IN SELECT unnest( in_array ) LOOP
        raise notice 't: %', t;
    END loop;
END;
$$ language plpgsql;
 
SELECT test( array['a', 'b', 'c'] );
psql:z.sql:15: NOTICE:  i: a
psql:z.sql:15: NOTICE:  i: b
psql:z.sql:15: NOTICE:  i: c
psql:z.sql:15: NOTICE:  t: a
psql:z.sql:15: NOTICE:  t: b
psql:z.sql:15: NOTICE:  t: c
 test
------
 
(1 row)

Now, you can use simpler syntax:

CREATE OR REPLACE FUNCTION test( in_array TEXT[] ) RETURNS void as $$
DECLARE
    t TEXT;
BEGIN
    FOREACH t IN ARRAY in_array LOOP
        raise notice 't: %', t;
    END loop;
END;
$$ language plpgsql;
 
SELECT test( array['a', 'b', 'c'] );
psql:z.sql:11: NOTICE:  t: a
psql:z.sql:11: NOTICE:  t: b
psql:z.sql:11: NOTICE:  t: c
 test
------
 
(1 row)

What is interesting, that when passing two dimensional array, it works like this:

SELECT test( '{{a,b,c},{d,e,f},{g,h,i}}' );
psql:z.sql:11: NOTICE:  t: a
psql:z.sql:11: NOTICE:  t: b
psql:z.sql:11: NOTICE:  t: c
psql:z.sql:11: NOTICE:  t: d
psql:z.sql:11: NOTICE:  t: e
psql:z.sql:11: NOTICE:  t: f
psql:z.sql:11: NOTICE:  t: g
psql:z.sql:11: NOTICE:  t: h
psql:z.sql:11: NOTICE:  t: i

If you'd prefer to iterate over sub arrays, it's simple thanks to “SLICE" syntax:

CREATE OR REPLACE FUNCTION test( in_array TEXT[] ) RETURNS void as $$
DECLARE
    t TEXT[];
BEGIN
    FOREACH t SLICE 1 IN ARRAY in_array LOOP
        raise notice 't: %', t;
    END loop;
END;
$$ language plpgsql;
 
SELECT test( '{{a,b,c},{d,e,f},{g,h,i}}' );
psql:z.sql:11: NOTICE:  t: {a,b,c}
psql:z.sql:11: NOTICE:  t: {d,e,f}
psql:z.sql:11: NOTICE:  t: {g,h,i}

All in all, it looks like a cool addition.

  1. 4 comments

  2. Mar 7, 2011

    Hello

    The parentheses around a variable are not necessary.

    Main goal of this functionality is effective iteration over large arrays

    Pavel

  3. Mar 7, 2011

    @Pavel:
    Thanks for info – removed them.

    Ah, so, as I understand it will be better/faster/less-memory-consuming than previous approaches? Nice.

  4. Mar 7, 2011

    The performance depends on usage – it should be always faster then FOR iteration with subscripts or via unnest:

    * one detoast
    * continuous seq scan of detoasted data
    * it uses a simply expression

    And it remove some pathological performance issue – so it can 30-40x and more faster than classic FOR

  5. Aug 4, 2016

    Thanks !!It help me two loop two dimensional array in pgsql …

Leave a comment