So I am trying to run this function
CREATE OR REPLACE FUNCTION TableIteration()
RETURNS TABLE(table_schema text, table_name text)
LANGUAGE plpgsql
AS
$$
DECLARE
tgt_schema varchar;
list varchar[] := ARRAY[
'sometext1',
'sometext2',
'sometext3',
'sometext4',
'sometext5',
'sometext6',
'sometext7',
'sometext8',
'sometext9'
];
BEGIN
FOREACH tgt_schema IN ARRAY list
LOOP
RETURN QUERY EXECUTE
'SELECT t.table_schema, t.table_name from information_schema.tables t';
END LOOP;
END
$$
And I am getting
ERROR: structure of query does not match function result type
Detail: Returned type information_schema.sql_identifier does not match
expected type text in column 1.
But if I change types to sql_identifier I can't create function because it says that there's no such type. So the question is what should i do?
The information schema columns have a strange data type (which - I think - is mandated by the SQL standard). Just cast them to text:
'SELECT t.table_schema::text, t.table_name::text from information_schema.tables t';
Related
I have this function that should be returning a varying columns, can I get a help on what is wrong with my code?
CREATE OR REPLACE FUNCTION functions.search(column_name VARCHAR(40))
RETURNS SETOF RECORD AS $$
DECLARE
rec RECORD;
BEGIN
RETURN QUERY EXECUTE format('SELECT %I FROM students_table);
END;
$$ LANGUAGE plpgsql;
Call:
SELECT * FROM functions.search(
('Student Id', 'Subect')
) as ("Student Id" bigint, "Subect" text)
Here's my error
ERROR: function functions.search(record) does not exist
LINE 1: SELECT * FROM functions.search(
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SQL state: 42883
Character: 15
Thank you very much
There are several things wrong here.
First, to support a variable number of arguments, you need a VARIADIC parameters. Then, your format function call is somewhat truncated and syntactical nonsense.
You could experiment with a function like this:
CREATE FUNCTION functions.search(VARIADIC column_names text[]) RETURNS SETOF record
LANGUAGE plpgsql AS
$$BEGIN
RETURN QUERY EXECUTE
format('SELECT %s FROM students_table',
(SELECT string_agg(quote_ident(s), ', ')
FROM unnest(column_names) AS cols(s))
);
END;$$;
You can call it like this:
SELECT *
FROM functions.search('Student Id', 'Subect')
AS ("Student Id" bigint, "Subect" text);
I am currently working a stored procedure capable of detecting continuity on a specific set of entries..
The specific set of entries is extracted from a sql query
The function takes in two input parameter, first being the table that should be investigated, and the other being the list of ids which should be evaluated.
For every Id I need to investigate every row provided by the select statement.
DROP FUNCTION IF EXISTS GapAndOverlapDetection(table_name text, entity_ids bigint[]);
create or replace function GapAndOverlapDetection ( table_name text, enteity_ids bigint[] )
returns table ( entity_id bigint, valid tsrange, causes_overlap boolean, causes_gap boolean)
as $$
declare
x bigint;
var_r record;
begin
FOREACH x in array $2
loop
EXECUTE format('select entity_id, valid from' ||table_name|| '
where entity_id = '||x||'
and registration #> now()::timestamp
order by valid ASC') INTO result;
for var_r in result
loop
end loop;
end loop ;
end
$$ language plpgsql;
select * from GapAndOverlapDetection('temp_country_registration', '{1,2,3,4}')
I currently get an error in the for statement saying
ERROR: syntax error at or near "$1"
LINE 12: for var_r in select entity_id, valid from $1
You can iterate over the result of the dynamic query directly:
create or replace function gapandoverlapdetection ( table_name text, entity_ids bigint[])
returns table (entity_id bigint, valid tsrange, causes_overlap boolean, causes_gap boolean)
as $$
declare
var_r record;
begin
for var_r in EXECUTE format('select entity_id, valid
from %I
where entity_id = any($1)
and registration > now()::timestamp
order by valid ASC', table_name)
using entity_ids
loop
... do something with var_r
-- return a row for the result
-- this does not end the function
-- it just appends this row to the result
return query
select entity_id, true, false;
end loop;
end
$$ language plpgsql;
The %I injects an identifier into a string and the $1 inside the dynamic SQL is then populated through passing the argument with the using keyword
Firstly, decide whether you want to pass the table's name or oid. If you want to identify the table by name, then the parameter should be of text type and not regclass.
Secondly, if you want the table name to change between executions then you need to execute the SQL statement dynamically with the EXECUTE statement.
I create a function and inside the function, I used predefined function array_to_string. When I try to execute my function I am getting the following error.
ERROR: function array_to_string(integer, unknown) does not exist
LINE 1: SELECT array_to_string(id, ',') FROM ame.stops where custome...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: SELECT array_to_string(id, ',') FROM ame.stops where customer_id=customer_id and driver_id=driver_id
CONTEXT: PL/pgSQL function ame.fn_get_stopids(integer,integer) line 4 at SQL statement
SQL state: 42883
When I use array_to_string in select statement it's working fine.
select array_to_string(array(SELECT id FROM ame.stops where customer_id='31' and driver_id='770'), ', ')
Function Code
CREATE OR REPLACE FUNCTION ame.fn_Get_StopIds(customer_id integer, driver_id integer)
RETURNS text AS $$
DECLARE StopIds text;
BEGIN
SELECT array_to_string(id, ',') FROM ame.stops where customer_id=customer_id and driver_id=driver_id into StopIds;
RETURN StopIds;
END;
$$ LANGUAGE plpgsql;
the function is expecting an array, but you are passing an integer (id).
In your working attempt, you are first converting the id to an array.
You may want to build the array first using array_agg
SELECT array_to_string(array_agg(id), ',')
FROM ame.stops
where customer_id=customer_id and driver_id=driver_id
into StopIds;
But then you don't need to build and concatenate the array, you can simply do
SELECT string_agg(id::text, ',')
FROM ame.stops
where customer_id=customer_id and driver_id=driver_id
into StopIds;
You may want to order by IDs
CREATE OR REPLACE FUNCTION ame.fn_get_stopids
(_customer_id integer,
_driver_id integer)
RETURNS text AS
$$
DECLARE
stopids text;
BEGIN
SELECT string_agg(id::text, ',') INTO stopids;
FROM ame.stops
WHERE customer_id = _customer_id
AND driver_id = _driver_id
RETURN stopids;
END;
$$
LANGUAGE plpgsql;
Say I have this query:
CREATE OR REPLACE FUNCTION select_from_table(table_name varchar(63))
RETURNS SETOF table_name AS
$$
DECLARE
query TEXT := 'SELECT * FROM ' || table_name;
BEGIN
RETURN QUERY EXECUTE query;
END;
$$ LANGUAGE plpgsql;
Now if I try to execute it, I get error: type "table_name" does not exist and that's probably because I can only use the parameters within the function (between the dollar quotes) and not in the return type definition.
The question would be: are there any ways to SELECT from a table by passing its name as a parameter instead of hard coding it to the function? How?
I want to get list of table names present in the view.
So I have created the function with one parameter(view_name) to get table names.
Function : funtion_GetTables_FromView
CREATE OR REPLACE FUNCTION funtion_GetTables_FromView
(
view_Name varchar
)
RETURNS TABLE
(
TableNames varchar
) AS
$BODY$
DECLARE
v_SQL varchar;
BEGIN
v_SQL := 'SELECT Table_Name
FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE
WHERE View_Name = ''' || view_Name || '''';
RAISE INFO '%',v_SQL;
RETURN QUERY EXECUTE v_SQL;
END;
$BODY$
LANGUAGE PLPGSQL;
Calling function:
select * from funtion_GetTables_FromView('myview');
But getting an error:
ERROR: structure of query does not match function result type
You only showed a part of the error message, the complete error message gives the actual reason:
ERROR: structure of query does not match function result type
Detail: Returned type information_schema.sql_identifier does not match expected type character varying in column 1.
Where: PL/pgSQL function funtion_gettables_fromview(character varying) line 14 at RETURN QUERY
So the column information_schema.table_name is not a varchar column. The immediate fix for this is to cast the column to the required type:
v_SQL := 'SELECT Table_Name::varchar
FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE
WHERE View_Name = ''' || view_Name || '''';
But the whole function is needlessly complex and error prone. A simply SQL function will do just fine:
CREATE OR REPLACE FUNCTION funtion_GetTables_FromView(v_viewname varchar)
RETURNS TABLE(tablenames varchar)
AS
$$
SELECT table_name
FROM information_schema.view_table_usage
WHERE view_Name = v_viewname;
$$
LANGUAGE sql;
For some reason this does not require the cast to varchar. I suspect this has something to do with running dynamic SQL inside PL/pgSQL.
Unrelated, but: I personally find it pretty useless to prefix a function with function_. It is obvious when using it, that it is a function. Are you prefixing all your classes with class_ and all your methods with method_ in your programming language?