I’m trying to create a function in PostgreSQL to get data from a table in a dynamic way, but if i update the structure of "my_table_2023", it will raise the error because the structure doesn’t match:
ERROR: structure of query does not match function result type
DETAIL: Returned type character varying(255) does not match expected type double precision in column 6.
CONTEXT: SQL statement "SELECT * FROM csv_congregational_ministries_2023_20240109090450;"
PL/pgSQL function dynamic_query_single_table(anyelement,integer) line 15 at RETURN QUERY
These are the functions and views used:
CREATE VIEW tables_per_year AS
SELECT DISTINCT ON (basename, yyyy) yyyy, id, name, basename
FROM (
SELECT
id,
created_at,
name,
CAST(SPLIT_PART(name, '_', -2) AS INTEGER) AS yyyy,
LEFT(name, POSITION('_' || CAST(SPLIT_PART(name, '_', -2) AS TEXT) IN name) - 1) AS basename
FROM "metabase_table"
WHERE name LIKE 'csv_%'
ORDER BY created_at DESC
) AS tables_per_year;
CREATE OR REPLACE FUNCTION get_table(_table_name text, year int)
RETURNS text AS $$
DECLARE
table_selected text;
BEGIN
EXECUTE 'SELECT name FROM tables_per_year WHERE name ILIKE $1 AND yyyy = $2 LIMIT 1;'
INTO table_selected
USING '%' || _table_name || '%', year;
RETURN table_selected::TEXT;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION dynamic_query_single_table(_table anyelement, _year int)
RETURNS SETOF anyelement AS $$
DECLARE
table_partial_name text;
table_selected text;
BEGIN
table_partial_name := pg_typeof(_table)::text;
table_selected := get_table(table_partial_name, _year);
EXECUTE FORMAT('DROP TABLE IF EXISTS %s; CREATE TABLE %s AS SELECT * FROM %s;', table_partial_name, table_partial_name, table_selected);
RETURN QUERY EXECUTE FORMAT('SELECT * FROM %s;', table_selected);
END;
$$ LANGUAGE plpgsql;
Query:
SELECT * FROM dynamic_query_single_table(NULL::my_table, 2023);
I’ve tried to run the DROP and CREATE in a query and call dynamic_query_single_table in two different queries and it works fine.
I think it doesn’t commit the queries with DROP TABLE and CREATE TABLE in dynamic_query_single_table because it’s a single transaction.
Thanks.
2
Answers
I solved using a TRIGGER and creating a function to create tables, this is the full code:
Thanks for your advices.
To be able to handle the issue that you are currently experiencing i would suggest you can use a combination of OUT parameters and EXECUTE statement to dynamically return the result.The following query below will create a function that has an OUT parameter called
result_table
that will hold the result set.The
EXECUTE
statement is used to dynamically fetch the result set from the dynamically created table. The query is as follows:After creating the following query you can declare the above function as follows:
The above function will help you handle the dynamic structure of the table and return the result set without having issues with the structure mismatch.