Pass multiple sets or arrays of values to a function

后端 未结 2 1739
悲&欢浪女
悲&欢浪女 2020-12-22 00:53

I\'m writing a PL/pgSQL function in PostgreSQL 9.3.10 to return who has attended certain classes/sessions from the following table:

Attendance
+-------+-----         


        
相关标签:
2条回答
  • 2020-12-22 01:24

    If you pass an array of records to the function it is simple:

    with attendance (class, section, name) as(values
        (1, 1, 'Amy'),
        (1, 1, 'Bill'),
        (1, 2, 'Charlie'),
        (1, 2, 'Dan'),
        (2, 1, 'Emily'),
        (2, 1, 'Fred'),
        (2, 2, 'George')
    )
    select *
    from attendance
    where (class, section) = any(array[(1,1),(2,2)])
    ;
     class | section |  name  
    -------+---------+--------
         1 |       1 | Amy
         1 |       1 | Bill
         2 |       2 | George
    
    0 讨论(0)
  • 2020-12-22 01:27

    You can achieve that with a simple SQL function. Key feature is the function generate_subscripts():

    CREATE OR REPLACE FUNCTION f_attendance(_arr2d int[])
      RETURNS SETOF attendance AS
    $func$
       SELECT a.*
       FROM   generate_subscripts($1, 1) i
       JOIN   attendance a ON a.class   = $1[i][1]
                          AND a.section = $1[i][2]
    $func$  LANGUAGE ROWS 10 sql STABLE;

    Call:

    SELECT * FROM f_attendance(ARRAY[[1,1],[2,2]]);
    

    Or the same with an array literal - which is more convenient in some contexts, especially with prepared statements:

    SELECT * FROM f_attendance('{{1,1},{2,2}}');
    

    The function always expects a 2D array. Even if you pass a single pair, nest it:

    SELECT * FROM f_attendance('{{1,1}}');
    

    Audit of your implementation

    1. You made the function VOLATILE, but it can be STABLE. Per documentation:

      Because of this snapshotting behavior, a function containing only SELECT commands can safely be marked STABLE.

      Related:

      • How to pass a parameter into a date function
    2. You also use LANGUAGE plpgsql instead of sql, which makes sense if you execute the function multiple times in the same session. But then you must also make it STABLE or you lose that potential performance benefit. The manual once more:

      STABLE and IMMUTABLE functions use a snapshot established as of the start of the calling query, whereas VOLATILE functions obtain a fresh snapshot at the start of each query they execute.

    3. Your EXPLAIN output shows an Index Only Scan, not a sequential scan like you suspect in your comment.

    4. There is also a sort step in your EXPLAIN output that does not match the code you show. Are you sure you copied the right EXPLAIN output? How did you obtain it anyway? PL/pgSQL functions are black boxes to EXPLAIN. Did you use auto_explain? Details:

      • Postgres query plan of a UDF invocation written in pgpsql
    5. The Postgres query planner has no idea how many array elements the passed parameter will have, so it is hard to plan the query and it may default to a sequential scan (depending on more factors). You can help by declaring the expected number of rows. If you typically don't have more than 10 items add ROWS 10 like I did now above. And test again.

    0 讨论(0)
提交回复
热议问题