I don't want to use joins because several phones for user are possible.
This is not a reason to avoid JOIN
s in PostgreSQL. At all.
PostgreSQL allows you to aggregate the phone numbers into an array:
CREATE OR REPLACE FUNCTION getUserById()
RETURNS TABLE (
id INTEGER,
name TEXT,
/* and other columns */
phone_numbers TEXT[]
)
AS
$$
select
users.id,
users.name,
/* and other columns */
-- Remove NULL because you get an array containing just NULL
-- if user_phones doesn't contain any matching rows.
array_remove(array_agg(user_phones.phone_number), NULL) as phone_numbers
from users
left join user_phones on user_phones.user_id = users.id
where users.id = 1
-- Note that grouping by a table's primary key allows you to use
-- any column from that table in the select in PostgreSQL
group by users.id
;
$$
LANGUAGE SQL
STABLE
;
This is much simpler and more intuitive.
You can switch to an inner join if it's okay to give back zero rows for a user without a phone number. In that case, you could drop the array_remove
call.
I also added the STABLE
specification to the function (since it doesn't modify any table data) and switched it to SQL
instead of PGPLSQL
(since it's just a single query). This will allow PG to optimize better; in particular, it can inline the query and push filters down in some cases. You may not even need a function, actually.