I have a simple query:
CREATE OR REPLACE FUNCTION companies_all_teams(
IN _company_name text = NULL,
IN _company_id int = NULL,
OUT _result text
)
AS
$$
BEGIN
_result := (SELECT json_agg(distinct(teams.name))
FROM jobs
JOIN companies
ON companies.id = jobs.company_id
JOIN teams
ON teams.id = jobs.team_id
WHERE lower(companies.name) = lower(_company_name)
AND jobs.is_disabled = false
);
END;
$$ LANGUAGE plpgsql;
There are two inputs, but only one of those is being used in the query. What is the simplest way to run the query conditionally based on which input we have?
Best Answer
If I understand correctly, you can sometimes provide
_company_id
directly, while you only have_company_name
in other situations. You do not intend to provide both at once.Since one parameter is of type
text
while the other isinteger
the most efficient solution for this case is probably function overloading. I.e., create two functions of the same name, one fortext
and another one forinteger
.While being at it, I suggest simple SQL functions for the simple task. The principal is the same as for plpgsql.
json_agg()
returns data typejson
, nottext
. Your plpgsql variant silently coerces the type in the assignment, but that's bad style. I made out the functions to returnjson
directly. You can cast totext
explicitly if you need to.1)
companies_all_teams(text)
2)
companies_all_teams(int)
Since we have two functions, we can optimize each for their input. Assuming referential integrity in your relational design, we don't need to join to
companies
at all, we already know thecompany_id
:To avoid ambiguity with overloaded function calls you need to provide explicitly typed values. In your simple case, however, it's still enough to use numeric literals (no single quotes) for
integer
or string literals (single quotes) fortext
.Call:
Related: