Return multiple fields as a record in PostgreSQL with PL/pgSQL

前端 未结 6 1378
生来不讨喜
生来不讨喜 2020-11-27 11:57

I am writing a SP, using PL/pgSQL.
I want to return a record, comprised of fields from several different tables. Could look something like this:

CREATE O         


        
6条回答
  •  生来不讨喜
    2020-11-27 12:19

    To return a single row

    Simpler with OUT parameters:

    CREATE OR REPLACE FUNCTION get_object_fields(_school_id int
                                           , OUT user1_id   int
                                           , OUT user1_name varchar(32)
                                           , OUT user2_id   int
                                           , OUT user2_name varchar(32)) AS 
    $func$
    BEGIN
       SELECT INTO user1_id, user1_name
              u.id, u.name
       FROM   users u
       WHERE  u.school_id = _school_id
       LIMIT  1;  -- make sure query returns 1 row - better in a more deterministic way?
    
       user2_id := user1_id + 1; -- some calculation
    
       SELECT INTO user2_name
              u.name       
       FROM   users u
       WHERE  u.id = user2_id;
    END
    $func$  LANGUAGE plpgsql;
    

    Call:

    SELECT * FROM get_object_fields(1);
    
    • You don't need to create a type just for the sake of this plpgsql function. It may be useful if you want to bind multiple functions to the same composite type. Else, OUT parameters do the job.

    • There is no RETURN statement. OUT parameters are returned automatically with this form that returns a single row. RETURN is optional.

    • Since OUT parameters are visible everywhere inside the function body (and can be used just like any other variable), make sure to table-qualify columns of the same name to avoid naming conflicts! (Better yet, use distinct names to begin with.)

    Simpler yet - also to return 0-n rows

    Typically, this can be simpler and faster if queries in the function body can be combined. And you can use RETURNS TABLE() (since Postgres 8.4, long before the question was asked) to return 0-n rows.

    The example from above can be written as:

    CREATE OR REPLACE FUNCTION get_object_fields2(_school_id int)
      RETURNS TABLE (user1_id   int
                   , user1_name varchar(32)
                   , user2_id   int
                   , user2_name varchar(32)) AS 
    $func$
    BEGIN
       RETURN QUERY
       SELECT u1.id, u1.name, u2.id, u2.name
       FROM   users u1
       JOIN   users u2 ON u2.id = u1.id + 1
       WHERE  u1.school_id = _school_id
       LIMIT  1;  -- may be optional
    END
    $func$  LANGUAGE plpgsql;
    

    Call:

    SELECT * FROM get_object_fields2(1);
    
    • RETURNS TABLE is effectively the same as having a bunch of OUT parameters combined with RETURNS SETOF record, just shorter.

    • The major difference: this function can return 0, 1 or many rows, while the first version always returns 1 row.
      Add LIMIT 1 like demonstrated to only allow 0 or 1 row.

    • RETURN QUERY is simple way to return results from a query directly.
      You can use multiple instances in a single function to add more rows to the output.

    db<>fiddle here (demonstrating both)

    Varying row-type

    If your function is supposed to dynamically return results with a different row-type depending on the input, read more here:

    • Refactor a PL/pgSQL function to return the output of various SELECT queries

提交回复
热议问题