Search code examples
postgresqlnpgsql

Filter Postgres table based on tuples of values


Imagine a table in Postgres:

Firstname     Surname      Age
------------------------------
Joe           Bloggs       5
Sam           Bloggs       7
Ellie         Jones        4
Mike          Smith        10

I would like to range-filter this, based on an array of pairs of values (tuples):

{Surname=Bloggs  &&   Age>=6 },
{Surname=Smith   &&   Age>=10}

To return:

Firstname     Surname      Age
------------------------------
Sam           Bloggs       7
Mike          Smith        10

I realise I can do this by hand-rolling a SQL statement like this:

SELECT * FROM MyTable t
WHERE (t.Surname = 'Bloggs' AND t.Age >= 6 )
OR    (t.Surname = 'Smith'  AND t.Age >= 10)

However, I need to call this from C#, and I'm interested in solutions which avoid having to generate a plain-text SQL statement for every query.

Is it possible to do this with a 'generic' SQL statement, passing in some kind of array of tuples / composite types as a filter parameter?

In other RDBMS I could, for example, populate a temporary table with the pairs of values, and join on that table; or use a table-valued-parameter (in SQL Server). Is there an equivalent in Postgres + NpgSql?

PS: I read in this question that using temporary tables for this may not be best practice in Postgres


Solution

  • The best solution we found was to pass in array of custom types, which you can then unnest into tabular form in the query, and join on to.

    CREATE TYPE predicate_type AS (
        Surname text,
        Age int);
    
    SELECT * FROM MyTable t
    JOIN unnest('{"(Bloggs, 6)","(Smith, 10)"}'::predicate_type[]) p(Surname, Age)
    ON t.Surname = p.Surname AND t.Age >= p.Age
    

    I've defined the array argument literally here, but you can pass them in as parameters to your query.

    For example, you can map an equivalent C# type to the Postgres type in Npgsql, then just pass a C# array of those types into your command as a parameter:
    https://www.npgsql.org/doc/types/enums_and_composites.html#mapping-your-clr-types