Functions returning TABLE in PostgreSQL - Time & Space Complexity
Start learning this pattern below
Jump into concepts and practice - no test required
When using functions that return tables in PostgreSQL, it's important to understand how the time to get results grows as the data grows.
We want to know how the function's execution time changes when the input or data size increases.
Analyze the time complexity of the following PostgreSQL function that returns a table.
CREATE FUNCTION get_active_users(min_age INT)
RETURNS TABLE(user_id INT, user_name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT id, name FROM users WHERE age >= min_age AND active = TRUE;
END;
$$ LANGUAGE plpgsql;
This function returns all active users who are at least a certain age.
Look for repeated actions inside the function.
- Primary operation: Scanning the users table to find matching rows.
- How many times: Once per function call, but the scan checks each row in the users table.
The function checks each user to see if they meet the age and active conditions.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 checks |
| 100 | About 100 checks |
| 1000 | About 1000 checks |
Pattern observation: The number of checks grows roughly in direct proportion to the number of users.
Time Complexity: O(n)
This means the time to run the function grows linearly with the number of users in the table.
[X] Wrong: "The function runs instantly no matter how many users there are because it's just a function."
[OK] Correct: The function still has to look at each user to check conditions, so more users mean more work and more time.
Understanding how functions that return tables scale helps you explain performance in real projects and shows you can think about data size effects clearly.
"What if the function used an index on the age column? How would the time complexity change?"
Practice
RETURNS TABLE do?Solution
Step 1: Understand the purpose of RETURNS TABLE
TheRETURNS TABLEclause defines that the function will return a set of rows with specified columns, like a table.Step 2: Compare with other return types
Unlike scalar returns or void,RETURNS TABLEreturns multiple rows and columns.Final Answer:
Returns multiple rows and columns as a table result -> Option CQuick Check:
RETURNS TABLE means multiple rows/columns [OK]
- Thinking RETURNS TABLE returns a single value
- Confusing RETURNS TABLE with RETURNS VOID
- Assuming it returns JSON automatically
id INT and name TEXT?Solution
Step 1: Check RETURNS TABLE syntax
CREATE FUNCTION f() RETURNS TABLE(id INT, name TEXT) AS $$ BEGIN RETURN QUERY SELECT 1, 'a'; END; $$ LANGUAGE plpgsql; correctly declaresRETURNS TABLE(id INT, name TEXT)matching the column names and types.Step 2: Verify RETURN QUERY usage
CREATE FUNCTION f() RETURNS TABLE(id INT, name TEXT) AS $$ BEGIN RETURN QUERY SELECT 1, 'a'; END; $$ LANGUAGE plpgsql; usesRETURN QUERY SELECT 1, 'a';which returns rows matching the table structure.Final Answer:
Correct RETURNS TABLE syntax and return statement -> Option DQuick Check:
RETURNS TABLE with matching columns and RETURN QUERY [OK]
- Using RETURNS SETOF RECORD without column definition
- Swapping column types in RETURNS TABLE
- Returning scalar instead of query
CREATE FUNCTION get_numbers() RETURNS TABLE(num INT) AS $$ BEGIN RETURN QUERY SELECT generate_series(1,3); END; $$ LANGUAGE plpgsql;
What will be the output of
SELECT * FROM get_numbers();?Solution
Step 1: Understand generate_series(1,3)
This function generates rows with values 1, 2, and 3.Step 2: RETURN QUERY returns all rows
The function returns all rows fromgenerate_series(1,3)as a table with columnnum.Final Answer:
3 rows with values 1, 2, 3 -> Option AQuick Check:
generate_series(1,3) returns 3 rows [OK]
- Thinking it returns a single row
- Confusing RETURNS TABLE with scalar return
- Expecting an error due to missing RETURNS SETOF
CREATE FUNCTION get_data() RETURNS TABLE(id INT, val TEXT) AS $$ BEGIN RETURN SELECT 1, 'a'; END; $$ LANGUAGE plpgsql;
Solution
Step 1: Check RETURN statement in RETURNS TABLE function
In PL/pgSQL, to return rows from a query, useRETURN QUERY, not justRETURN.Step 2: Identify missing RETURN QUERY
The function usesRETURN SELECTwhich is invalid syntax; it should beRETURN QUERY SELECT.Final Answer:
Missing RETURN QUERY before SELECT -> Option AQuick Check:
Use RETURN QUERY to return rows in RETURNS TABLE [OK]
- Using RETURN instead of RETURN QUERY for table results
- Omitting LANGUAGE plpgsql
- Incorrect RETURNS TABLE column types
users table with columns id INT and name TEXT. Which function definition correctly achieves this?Solution
Step 1: Match RETURNS TABLE columns with SELECT output
The function returnsid INTandname TEXT, so the SELECT must output these types. CREATE FUNCTION get_upper_users() RETURNS TABLE(id INT, name TEXT) AS $$ BEGIN RETURN QUERY SELECT id, UPPER(name) FROM users; END; $$ LANGUAGE plpgsql; matches this.Step 2: Check the transformation applied
CREATE FUNCTION get_upper_users() RETURNS TABLE(id INT, name TEXT) AS $$ BEGIN RETURN QUERY SELECT id, UPPER(name) FROM users; END; $$ LANGUAGE plpgsql; usesUPPER(name)to convert names to uppercase as required.Step 3: Verify other options
CREATE FUNCTION get_upper_users() RETURNS TABLE(id INT, name TEXT) AS $$ BEGIN RETURN QUERY SELECT id, LOWER(name) FROM users; END; $$ LANGUAGE plpgsql; uses LOWER instead of UPPER, CREATE FUNCTION get_upper_users() RETURNS SETOF record AS $$ BEGIN RETURN QUERY SELECT id, UPPER(name) FROM users; END; $$ LANGUAGE plpgsql; returns SETOF record (no column definition), CREATE FUNCTION get_upper_users() RETURNS TABLE(id TEXT, name TEXT) AS $$ BEGIN RETURN QUERY SELECT id, UPPER(name) FROM users; END; $$ LANGUAGE plpgsql; mismatches id type (TEXT instead of INT).Final Answer:
Correctly returns id and uppercase name as a table -> Option BQuick Check:
RETURNS TABLE with matching columns and UPPER(name) [OK]
- Using LOWER instead of UPPER
- Mismatching column types in RETURNS TABLE
- Using SETOF record instead of RETURNS TABLE
