Declaring the tuple structure of a record in PL/pgSQL

前端 未结 3 1224
心在旅途
心在旅途 2020-12-10 21:02

I can\'t find anything in the PostgreSQL documentation that shows how to declare a record, or row, while declaring the tuple structure at the same time. If you don\'t define

相关标签:
3条回答
  • 2020-12-10 21:32

    There might be some way that avoids the explicit type declaration, but offhand the best I can come up with is:

    CREATE TYPE my_func_return AS (
        a integer,
        b varchar
      );
    
    CREATE OR REPLACE FUNCTION my_func()
      RETURNS my_func_return AS $$
    DECLARE
      r my_func_return;
    BEGIN
      SELECT 1, 'one' INTO r.a, r.b;
      RETURN r;
    END; $$ LANGUAGE plpgsql;
    

    Oh, I almost forgot the simplest way to do this:

    CREATE OR REPLACE FUNCTION my_func2(out a int, out b text)
      RETURNS RECORD AS $$
    BEGIN
      SELECT 1, 'one' INTO a, b;
      RETURN;
    END; $$ LANGUAGE plpgsql;
    
    0 讨论(0)
  • 2020-12-10 21:35

    You are mixing the syntax for returning SETOF values with syntax for returning a single row or value.

    -- A related question is - how do I return the single record 'r' from

    When you declare a function with RETURNS TABLE, you have to use RETURN NEXT in the body to return a row (or scalar value). And if you want to use a record variable with that it has to match the return type. Refer to the code examples further down.

    Return a single value or row

    If you just want to return a single row, there is no need for a record of undefined type. @Kevin already demonstrated two ways. I'll add a simplified version with OUT parameters:

    CREATE OR REPLACE FUNCTION my_func(OUT a integer, OUT b text)
       AS
    $func$
    BEGIN
       a := ...;
       b := ...;
    END
    $func$ LANGUAGE plpgsql;
    

    You don't even need to add RETURN; in the function body, the value of the declared OUT parameters will be returned automatically at the end of the function - NULL for any parameter that has not been assigned.
    And you don't need to declare RETURNS RECORD because that's already clear from the OUT parameters.

    Return a set of rows

    If you actually want to return multiple rows (including the possibility for 0 or 1 row), you can define the return type as RETURNS ...

    • SETOF some_type, where some_type can be any registered scalar or composite type.

    • TABLE (col1 type1, col2 type2) - an ad-hoc row type definition.

    • SETOF record plus OUT parameters to define column names andtypes.
      100% equivalent to RETURNS TABLE.

    • SETOF record without further definition. But then the returned rows are undefined and you need to include a column definition list with every call (see example).

    The manual about the record type:

    Record variables are similar to row-type variables, but they have no predefined structure. They take on the actual row structure of the row they are assigned during a SELECT or FOR command.

    There is more, read the manual.

    You can use a record variable without assigning a defined type, you can even return such undefined records:

    CREATE OR REPLACE FUNCTION my_func()
      RETURNS SETOF record AS
    $func$
    DECLARE
        r record;
    BEGIN
        r := (1::int, 'foo'::text); RETURN NEXT r; -- works with undefined record
        r := (2::int, 'bar'::text); RETURN NEXT r;
    END
    $func$ LANGUAGE plpgsql;
    

    Call:

    SELECT * FROM my_func() AS x(a int, b text);
    

    But this is very unwieldy as you have to provide the column definition list with every call. It can generally be replaced with something more elegant:

    • If you know the type at time of function creation, declare it right away (RETURNS TABLE or friends).

    CREATE OR REPLACE FUNCTION my_func()
      RETURNS SETOF tbl_or_type AS
    $func$
    DECLARE
        r tbl_or_type;
    BEGIN
        SELECT INTO tbl_or_type  * FROM tbl WHERE id = 10;
        RETURN NEXT r;  -- type matches
    
        SELECT INTO tbl_or_type  * FROM tbl WHERE id = 12;
        RETURN NEXT r;
    
        -- Or simpler:
        RETURN QUERY
        SELECT * FROM tbl WHERE id = 14;
    END
    $func$ LANGUAGE plpgsql;
    
    • If you know the type at time of the function call, there are more elegant ways using polymorphic types:
      Refactor a PL/pgSQL function to return the output of various SELECT queries

    Your question is unclear as to what you need exactly.

    0 讨论(0)
  • 2020-12-10 21:44

    It is much easier to use OUT parameters rather than a record. If iteratively building a set of records (a table) use RETURN NEXT. If generating from a query, use RETURN QUERY. See:

    https://stackoverflow.com/a/955289/398670

    and:

    http://www.postgresql.org/docs/current/static/plpgsql-declarations.html http://www.postgresql.org/docs/current/static/sql-createfunction.html http://www.postgresonline.com/journal/archives/129-Use-of-OUT-and-INOUT-Parameters.html

    Think:

    CREATE OR REPLACE FUNCTION my_func(OUT a integer, OUT b varchar) RETURNS SETOF RECORD AS $$
    BEGIN
        -- Assign a and b, RETURN NEXT, repeat. when done, RETURN.
    END;
    $$ LANGUAGE 'plpgsql';  
    
    0 讨论(0)
提交回复
热议问题