Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use `RETURN NEXT`in PL/pgSQL correctly?

I am trying to write a loop using PL/pgSQL (PostgreSQL 9.3) function that returns a table. I used RETURN NEXT; with no parameters after each query in the loop, following examples found like plpgsql error "RETURN NEXT cannot have a parameter in function with OUT parameters" in table-returning function, and elsewhere. However, I am still getting an error that says:

ERROR:  query has no destination for result data
HINT:  If you want to discard the results of a SELECT, use PERFORM instead.

A minimal code example to reproduce the problem is below. Can anyone please help explain how to fix the test code to return a table?

Thanks in advance.

Minimal example:

CREATE OR REPLACE FUNCTION test0()
 RETURNS TABLE(y integer, result text) AS $func$
DECLARE
    yr RECORD;
BEGIN
    FOR yr IN SELECT * FROM generate_series(1,10,1) AS y_(y) 
    LOOP
        RAISE NOTICE 'Computing %', yr.y;
        SELECT yr.y, 'hi';
        RETURN NEXT;
    END LOOP;
    RETURN;
END
$func$ LANGUAGE plpgsql;
like image 695
thor Avatar asked Dec 27 '14 00:12

thor


People also ask

How do I return a record in PostgreSQL?

To return a table from the function, you use RETURNS TABLE syntax and specify the columns of the table. Each column is separated by a comma (, ). In the function, we return a query that is a result of a SELECT statement.

What is $$ in PostgreSQL?

It can be used to replace single quotes enclosing string literals (constants) anywhere in SQL scripts. The body of a function happens to be such a string literal. Dollar-quoting is a PostgreSQL-specific substitute for single quotes to avoid escaping of nested single quotes (recursively).

What is the correct syntax of writing if/then statement in PL pgSQL?

Syntax: IF condition THEN statements; END IF; The above conditional statement is a boolean expression that evaluates to either true or false.

Can you loop in PostgreSQL?

Postgresql supports For loop statements to iterate through a range of integers or results from a sequence query. The For loop is used to iterate over a set of numbers or objects.


1 Answers

The example given may be wholly replaced with RETURN QUERY:

BEGIN
    RETURN QUERY SELECT y_.y, 'hi' FROM generate_series(1,10,1) AS y_(y)
END;

which will be a lot faster.

In general you should avoid iteration wherever possible, and instead favour set-oriented operations.

Where return next over a loop is unavoidable (which is very rare, and mostly confined to when you need exception handling) you must set OUT parameter values or table parameters, then return next without arguments.

In this case your problem is the line SELECT yr.y, 'hi'; which does nothing. You're assuming that the implicit destination of a SELECT is the out parameters, but that's not the case. You'd have to use the out parameters as loop variables like @peterm did, use assignments or use SELECT INTO:

FOR yr IN SELECT * FROM generate_series(1,10,1) AS y_(y) 
LOOP
    RAISE NOTICE 'Computing %', yr.y;
    y := yr.y;
    result := 'hi';
    RETURN NEXT;
END LOOP;
RETURN;
like image 192
Craig Ringer Avatar answered Nov 08 '22 20:11

Craig Ringer