I created a function to get me a value of the current date in yyyymmdd format.
create or replace function currdate() returns text as $$ select 'account_'||TO_CHAR(current_date , 'yyyymmdd');
$$ LANGUAGE sql;
Now i have to write a Proc to append this date 'yyyymmdd' to a create a snapshot table that will be created on the 1st and last day of the month.
I wrote the below Proc
create or replace procedure proc_1() AS $$
declare
dttoday text := currdate();
int_check int := checkint();
begin
if int_check = 1 then
create table **schema.snapshot_currdate** as (select * from schema1.original_table); end if;
end;
$$
language plpgsql;
Here when the table is created : snapshot_currdate I need it to be created as name snapshot_yyyymmdd (Date it was executed)
Declared Variable int_check is a function that checks if its 1st or last day of the month it will return integer value 1
Any Ideas?
FYI, Postgres 9.1 is four years past EOL.
Something like:
currdate() returns text as $$ select 'account_'||TO_CHAR(current_date , 'yyyymmdd');
$$ LANGUAGE sql;
CREATE OR REPLACE PROCEDURE public.proc_1()
LANGUAGE plpgsql
AS $procedure$
declare
dttoday text := currdate();
begin
EXECUTE 'create table '|| quote_ident('public')||'.'||quote_ident('snapshot_'||split_part(dttoday, '_', 2))||'()';
RAISE NOTICE '%', dttoday;
end;
$procedure$
The split_part is because currdate() returns account_yyyymmdd and you say you want snapshot_yyyymmdd. For more information on dynamic commands see here:
https://www.postgresql.org/docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
Related
I have written a stored procedure as below but I am not able to dynamically append today's date into my table name. The below code gives me an error "Invalid Operation: syntax error" while calling the stored procedure. Thank you in advance
CREATE OR REPLACE PROCEDURE schema.reftable (vname date)
AS $$
DECLARE tname VARCHAR(50):= 'schema.MT_'||QUOTE_LITERAL(vname) ;
BEGIN
execute
'create table ' || tname || ' as select current_date as upload_date, * from schema.test';
END;
$$ LANGUAGE plpgsql
;
-- Calling the stored procedure
call schema.reftable(current_date);
I have 30 state wise data tables. Table name like aa_shg_detail, ab_shg_detail, ac_shg_detail.
I have also main state table in which state short names and state codes are stored. I have created 2 postgresql functions getTableName(Code text) and getDataByTable().
In the first function I pass the state code so it fetches the state short name and short name concat with _shg_detail String and prepare full table name and return it. Example: If I pass state code 2 the query fetch state short name based on state code 2 from the state's main table. The state short name is 'ab' for state code 2 so after concat state short name with _shg_detail first function return ab_shg_detail table name.
Second function gets the table name from first function and fetch data from that table. But I am getting error in the second function.
CREATE OR REPLACE FUNCTION getTableName(code text)
RETURNS text
AS $$
select concat(lower(state_short_name), '_shg_detail') from main_state where state_code = code))
$$
LANGUAGE sql;
CREATE OR REPLACE FUNCTION getDataByTable()
RETURNS text AS $$
DECLARE
tablename text;
BEGIN
tablename := gettablename('2');
RETURN (select shg_code from tablename);
END;
$$ LANGUAGE plpgsql;
When I execute a second function select getDataByTable() then I am getting this error every time:
ERROR: relation "tablename" does not exist
LINE 1: SELECT (select shg_code from tableName)
You need dynamic SQL for that:
CREATE OR REPLACE FUNCTION getDataByTable()
RETURNS text AS $$
DECLARE
tablename text;
l_result text;
BEGIN
tablename := gettablename('2');
execute format('select shg_code from %I', tablename)
into l_result;
RETURN l_result;
END;
$$ LANGUAGE plpgsql;
The %I placeholder of the format() function properly deals with quoting of identifiers if needed.
I have 30 state wise data tables. Table name like aa_shg_detail, ab_shg_detail, ac_shg_detail.
I have also main state table in which state short names and state codes are stored. I have created 2 postgresql functions getTableName(Code text) and getDataByTable().
In the first function I pass the state code so it fetches the state short name and short name concat with _shg_detail String and prepare full table name and return it. Example: If I pass state code 2 the query fetch state short name based on state code 2 from the state's main table. The state short name is 'ab' for state code 2 so after concat state short name with _shg_detail first function return ab_shg_detail table name.
Second function gets the table name from first function and fetch data from that table. But I am getting error in the second function.
CREATE OR REPLACE FUNCTION getTableName(code text)
RETURNS text
AS $$
select concat(lower(state_short_name), '_shg_detail') from main_state where state_code = code))
$$
LANGUAGE sql;
CREATE OR REPLACE FUNCTION getDataByTable()
RETURNS text AS $$
DECLARE
tablename text;
BEGIN
tablename := gettablename('2');
RETURN (select shg_code from tablename);
END;
$$ LANGUAGE plpgsql;
When I execute a second function select getDataByTable() then I am getting this error every time:
ERROR: relation "tablename" does not exist
LINE 1: SELECT (select shg_code from tableName)
You need dynamic SQL for that:
CREATE OR REPLACE FUNCTION getDataByTable()
RETURNS text AS $$
DECLARE
tablename text;
l_result text;
BEGIN
tablename := gettablename('2');
execute format('select shg_code from %I', tablename)
into l_result;
RETURN l_result;
END;
$$ LANGUAGE plpgsql;
The %I placeholder of the format() function properly deals with quoting of identifiers if needed.
I'm trying to get a customer id which can be placed in one of ten different tables. I don't want to hard code those table names to find it so I tried postgresql function as follows.
create or replace FUNCTION test() RETURNS SETOF RECORD AS $$
DECLARE
rec record;
BEGIN
select id from schema.table_0201_0228 limit 1 into rec;
return next rec;
select id from schema.table_0301_0331 limit 1 into rec;
return next rec;
END $$ language plpgsql;
select * from test() as (id int)
As I'm not familiar with postgresql function usage, how can I improve the code to replace 'schema.table1' with a variable, loop each table and return the result?
NOTE: table names may change overtime. For example, table_0201_0228 and table_0301_0331 are for February and March respectively.
You need dynamic SQL for that:
create or replace FUNCTION test(p_schema text)
RETURNS table(id int)
AS $$
DECLARE
l_tab record;
l_sql text;
BEGIN
for l_tab in (select schemaname, tablename
from pg_tables
where schemaname = p_schema)
loop
l_sql := format('select id from %I.%I limit 1', l_tab.schemaname, l_tab.tablename);
return query execute l_sql;
end loop;
END $$
language plpgsql;
I made the schema name a parameter, but of course you can hard-code it. As the function is defined as returns table there is no need to specify the column name when using it:
select *
from test('some_schema');
I want to select persons from a table where the date is within a given month.
This is what I have so far, but it's not working:
CREATE OR REPLACE FUNCTION u7()
RETURNS character varying AS
$BODY$
DECLARE
data varchar=`data`;
mes varchar=`2016-11-21`;
incidencia varchar=`expulsions`;
valor varchar;
BEGIN
EXECUTE `SELECT `
||quote_ident(data)
||`FROM `
||quote_ident(incidencia)
||` WHERE data IN(select date_part(`month`, TIMESTAMP $1))`
INTO valor USING mes;
return valor;
END;
$BODY$
LANGUAGE plpgsql;
select * FROM u7();
Clean syntax for what you are trying to do could look like this:
CREATE OR REPLACE FUNCTION u7()
RETURNS TABLE (valor text) AS
$func$
DECLARE
data text := 'data'; -- the first 3 would typically be function parameters
incidencia text := 'expulsions';
mes timestamp = '2016-11-21';
mes0 timestamp := date_trunc('month', mes);
mes1 timestamp := (mes0 + interval '1 month');
BEGIN
RETURN QUERY EXECUTE format(
'SELECT %I
FROM %I
WHERE datetime_column_name >= $1
AND datetime_column_name < $2'
, data, incidencia)
USING mes0, mes1;
END
$func$ LANGUAGE plpgsql;
SELECT * FROM u7();
Obviously, data cannot be a text column and a timestamp or date column at the same time. I use datetime_column_name for the timestamp column - assuming it's data type timestamp.
Aside from various syntax errors, do not use the construct with date_part(). This way you would have to process every row of the table and could not use an index on datetime_column_name - which my proposed alternative can.
See related answers for explanation:
EXECUTE...INTO...USING statement in PL/pgSQL can't execute into a record?
Table name as a PostgreSQL function parameter
How do I match an entire day to a datetime field?