How to apply a function to each element of an array column in Postgres?

后端 未结 4 697
遇见更好的自我
遇见更好的自我 2020-12-07 20:32

A Pg query returns an array. I would like to retrieve that with each element formatted to 3 decimal places. How can I apply a function to each element of an array? Something

4条回答
  •  春和景丽
    2020-12-07 20:55

    You need to turn the array into a row set. For example, using generate_series:

    SELECT ARRAY(SELECT ROUND(ARRAY[1.53224,0.23411234])[i], 2) FROM generate_series(1,2) AS s(i));    
    

    I know that's pretty ugly. There should be a helper function to make such mappings easier.

    Perhaps something like (yes it's horrible, slow, and brittle dynamic code):

    CREATE OR REPLACE FUNCTION map_with_arg(TEXT, ANYARRAY, TEXT)
    RETURNS ANYARRAY
    IMMUTABLE STRICT
    LANGUAGE 'plpgsql' AS
    $$
    DECLARE
        i INTEGER;
        t TEXT;
        cmd TEXT;
    BEGIN
        FOR i IN array_lower($2, 1) .. array_upper($2, 1) LOOP
            cmd := 'SELECT ('||quote_ident($1)||'('||quote_nullable($2[i])||', '||quote_nullable($3)||'))::TEXT';
            EXECUTE cmd INTO t;
            $2[i] := t;
        END LOOP;
        RETURN $2;
    END;
    $$;
    
    select map_with_arg('repeat', array['can','to']::TEXT[], '2');
     map_with_arg
    ---------------
     {cancan,toto}
    

    Update It occurs to me that we could use a single dynamic statement for the whole loop. This could mitigate some of the performance concerns.

    CREATE OR REPLACE FUNCTION map_with_arg(TEXT, ANYARRAY, TEXT)
    RETURNS ANYARRAY
    IMMUTABLE STRICT
    LANGUAGE 'plpgsql' AS
    $$
    DECLARE
        cmd TEXT;
        rv TEXT;
    BEGIN
        cmd := 'SELECT ARRAY(SELECT (' || quote_ident($1)||'($1[i], '||quote_nullable($3)||'))::TEXT FROM generate_subscripts($1, 1) AS gs(i))';
        EXECUTE cmd USING $2 INTO rv;
        RETURN rv;
    END;
    $$;
    

提交回复
热议问题