Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL - RETURNING INTO array

I want to store an update's RETURNING values into a data structure so that I can use it in a subsequent query.

In this example, I'm given a list of "parent_ids", and I want to find all children whose parent is in that array. Then, I wish to update some value on them, and do other stuff.

CREATE OR REPLACE FUNCTION plpgsql_is_really_great(parent_ids bigint[])
  RETURNS void AS
$$
DECLARE
    found_ids bigint[];
BEGIN    
    UPDATE child SET
        foo = bar
    FROM 
        (SELECT id
            FROM child
            WHERE parent_id=ANY(parent_ids)
        ) as children_ids
    WHERE
        child.id = children_ids.id
    RETURNING children_ids.id INTO found_ids;  -- ???

    -- do more stuff with found_ids
$$ LANGUAGE plpgsql
like image 931
JS_Riddler Avatar asked Nov 18 '14 21:11

JS_Riddler


People also ask

How do I return an array in PostgreSQL?

CREATE OR REPLACE FUNCTION contact_countries_array(INT) RETURNS ANYARRAY AS ' SELECT ARRAY[contacts_primarycountry, contacts_othercountry] FROM contacts WHERE contacts_id = $1' LANGUAGE SQL; The data type of contacts_primarycountry and contacts_othercountry is integer. contacts_id is unique and integer.

What does returning do in Postgres?

A common shorthand is RETURNING * , which selects all columns of the target table in order. In an INSERT , the data available to RETURNING is the row as it was inserted. This is not so useful in trivial inserts, since it would just repeat the data provided by the client.

What is select for update Postgres?

The select ... for update acquires a ROW SHARE LOCK on a table. This lock conflicts with the EXCLUSIVE lock needed for an update statement, and prevents any changes that could happen concurrently. All the locks will be released when the transaction ends.


2 Answers

There are a few ways to go about this.

Say you want to call some f(id) for each id affected by the UPDATE.

In PL/pgSQL:

$$ 
DECLARE found_id BIGINT;
BEGIN
  FOR found_id IN (UPDATE child SET foo=bar RETURNING id) LOOP
    PERFORM f(found_id);
  END LOOP;
END
$$

In pure SQL:

WITH updated(found_id) AS (
  UPDATE child SET foo=bar RETURNING id
)
SELECT f(found_id) FROM updated;

If you want to collect all the found_ids in an array, you can simply:

$$
DECLARE array_var BIGINT[];
BEGIN
  WITH updated(found_id) AS (
    UPDATE child SET foo=bar RETURNING id
  )
  SELECT array_agg(found_id) FROM updated INTO array_var;
END
$$
like image 118
Nick Barnes Avatar answered Sep 21 '22 08:09

Nick Barnes


Here is an example:

CREATE OR REPLACE FUNCTION exemplary ( parent_ids bigint[] )
RETURNS VOID AS $$
DECLARE
    _found_ids bigint[];
BEGIN

    WITH matching_children AS (
        UPDATE child
        SET foo = 1
        WHERE parent_id = ANY ( parent_ids )
        RETURNING id
    )
    SELECT array_agg ( id )
    FROM matching_children
    INTO _found_ids;

    RAISE NOTICE '%', _found_ids;

    RETURN;

END $$ LANGUAGE plpgsql;
like image 27
Tomasz Siorek Avatar answered Sep 24 '22 08:09

Tomasz Siorek