postgres function not excuting properly: syntax error - sql

CREATE OR REPLACE FUNCTION deleteWeekAggTables (tablename TEXT, Duration TEXT) RETURNS INTEGER as $$
DECLARE
startWeek INTEGER;
endWeek INTEGER;
BEGIN
startWeek= EXTRACT(YEAR FROM (CURRENT_DATE - INTERVAL ''||Duration||'') ) * 100 + EXTRACT(WEEK FROM (CURRENT_DATE - INTERVAL ''||Duration||'')) ;
endWeek = EXTRACT(YEAR FROM CURRENT_DATE) * 100 + EXTRACT(WEEK FROM CURRENT_DATE) ;
EXECUTE ' DELETE FROM '||tablename||'
WHERE date_dimension_year * 100 + date_dimension_week
NOT BETWEEN '||startWeek||' AND '||endWeek||' ' ;
RETURN 1;
END;
$$ LANGUAGE plpgsql;
I get error on calling this function I dont know what is the issue here as per logic it should pas the duration as parameter
6 [SELECT - 0 row(s), 0.000 secs] [Error Code: 0, SQL State: 22007] ERROR: invalid input syntax for type interval: ""
Where: PL/pgSQL function deleteweekaggtables(text,text) line 7 at assignment
... 1 statement(s) executed, 0 row(s) affected, exec/fetch time: 0.000/0.000 sec [0 successful, 0 warnings, 1 errors]
on calling the function :
select deleteWeekAggTables('raj_weekly','13 months');
Ok it works now although I have a similar problem with another function :
Create Or Replace Function DelAggRecords (tablename TEXT, Duration interval) Returns integer as $$
Begin
execute ' delete from '||tablename|| '
where now() - cast(date_dimension_year||''-''||date_dimension_month||''-''||date_dimension_day AS date) > 'Duration;
RETURN 1;
END;
$$ LANGUAGE plpgsql;
select DelAggRecords('raj_test','13 months'::interval);

The easiest is to pass an interval to the function
select deleteWeekAggTables('raj_weekly','13 months'::interval);
create or replace function deleteweekaggtables (
tablename text, duration interval
) returns integer as $$
startweek =
extract(year from (current_date - duration) ) * 100 +
extract(week from (current_date - duration)) ;

Related

ERROR: function pg_catalog.extract(unknown, integer) does not exist

I am writing an SQL query for creating the partitions which looks like:
DO
$$
DECLARE
table_name text := 'table_1';
start_date date := (SELECT MIN(create_date)
FROM db.table);
end_date date := (SELECT MAX(create_date)
FROM db.table);
partition_interval interval := '1 day';
partition_column_value text;
BEGIN
FOR partition_column_value IN SELECT start_date +
(generate_series * extract(day from partition_interval)::integer)::date
FROM generate_series(0, extract(day from end_date - start_date::date) /
extract(day from partition_interval))
LOOP
EXECUTE format(
'create table if not exists %1$s_%2$s partition of %1$s for values in (%2$s) partition by list (create_date)',
table_name, partition_column_value::date);
END LOOP;
END
$$;
I get an error:
[42883] ERROR: function pg_catalog.extract(unknown, integer) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Where: PL/pgSQL function inline_code_block line 9 at FOR over SELECT rows
The immediate cause of the error msg is this:
extract(day from end_date - start_date::date)
It's nonsense to cast start_date::date, start_date being type date to begin with. More importantly, date - date yields integer (not interval like you might assume). And extract() does not operate on integer input.
I removed more confusion and noise to arrive at this:
DO
$do$
DECLARE
table_name text := 'table_1';
partition_interval integer := 1; -- given in days!!
start_date date;
end_date date;
partition_column_value text;
BEGIN
SELECT INTO start_date, end_date -- two assignments for the price of one
min(create_date), max(create_date)
FROM db.table;
FOR partition_column_value IN
SELECT start_date + g * partition_interval -- date + int → date
FROM generate_series(0, (end_date - start_date) -- date - date → int
/ partition_interval) g
LOOP
EXECUTE format(
'CREATE TABLE IF NOT EXISTS %1$I PARTITION OF %1$I
FOR VALUES IN (%3$L) PARTITION BY LIST (create_date)'
, table_name || to_char(partition_column_value, '"_"yyyymmdd') -- !
, table_name
, partition_column_value::text -- only covers single day!!
);
END LOOP;
END
$do$;
This should work.
But it only makes sense for the example interval of '1 day'. For longer intervals, concatenate the list of days per partition or switch to range partitioning ...

PostgreSQL function Return table

i want to setup a function on PostgreSQL which returns a table. This is the source code of the function:
CREATE OR REPLACE FUNCTION feiertag(inDate Date)
RETURNS TABLE (eingabeDatum DATE, f_heute INT, f_1 INT, f_2 INT, f_3 INT, f_5 INT)
AS $$
DECLARE
f_heute integer := 0;
f_1 integer := 0;
f_2 integer := 0;
f_3 integer := 0;
f_5 integer := 0;
BEGIN
SELECT 1 INTO f_heute FROM feiertage where datum = inDate;
SELECT 1 INTO f_1 FROM feiertage where datum = (inDate + interval '1' day);
SELECT 1 INTO f_2 FROM feiertage where datum = (inDate + interval '2' day);
SELECT 1 INTO f_3 FROM feiertage where datum = (inDate + interval '3' day);
SELECT 1 INTO f_5 FROM feiertage where datum = (inDate + interval '5' day);
RETURN QUERY SELECT inDate as eingabeDatum, coalesce(f_heute, 0) as f_heute, coalesce(f_1,0) as f_1, coalesce(f_2,0) as f_2, coalesce(f_3,0) as f_3, coalesce(f_5,0) as f_5 ;
END;
$$ LANGUAGE plpgsql;
Calling the function returns only one column with ',' separated values:
psql (9.5.12)
Type "help" for help.
tarec=> select feiertag('2017-01-01');
feiertag
------------------------
(2017-01-01,1,0,0,0,0)
(1 row)
I expected differnt columns (one for each value as the table is specified at the beginning of the function) and not only one with all values. Does anybody know why this is happening and how i could fix this?
Thanks
Timo
Use
SELECT *
FROM feiertag('2017-01-01');
instead of
SELECT feiertag('2017-01-01');
to get the result as a table.
(Treat the function as if it were a table.)

How to dynamically select into query

EXECUTE format(
'SELECT MAX(sum)
FROM table 1
WHERE %s = %s') INTO max_value USING id_column, id_value;
Getting error: ERROR: operator does not exist: character varying =
integer.
Also, when I try to run the below code:
update table1 set column2 = max_value + sum;
I get another error:
"ERROR: column "max_value" does not exist"
You can use this:
CREATE OR REPLACE FUNCTION maxvaloftable ()
RETURNS integer AS
$BODY$
DECLARE
resultat integer = 2;
BEGIN
resultat= (SELECT MAX(sum) FROM table) ;
RETURN resultat;
END;
$BODY$
LANGUAGE plpgsql VOLATILE STRICT
COST 100;
ALTER FUNCTION maxvaloftable()
OWNER TO postgres;
update table1 set column2 = (select maxvaloftable ()) + sum;

ORA-06502 when comparing of Number datatype of ORA-06502 when querying AS400 table through ORACLE DBMS_HS_PASSTHROUGH

I'm trying to convert number format which is date "YYYYMMDD" to user specified date like "Last 7 days / 1 month data" using DBMS_HS_PASSTHROUGH from oracle database.
This query runs fine on AS400:
SELECT * FROM AGNTPF
WHERE
START_DATE >= DEC(REPLACE(CHAR(CURRENT_DATE - 1 MONTH, ISO), '-', ''), 8, 0) )
but when I run it from oracle using gateway
declare
ret integer;
begin
ret := dbms_hs_passthrough.execute_immediate#P400(
'create TABLE AGNTPF1 AS
(SELECT * FROM AGNTPF WHERE START_DATE >= DEC(REPLACE(CHAR(CURRENT_DATE - 1 MONTH, ISO), '-', ''), 8, 0) ) with data');
end;
/
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at line 4
Regards,
Gaurav
I don't know about db2400 / AS400, but to me, it looks like the SQL statement you pass to your procedure lacks proper escaping of the quotes. This should work:
declare
ret integer;
begin
ret := dbms_hs_passthrough.execute_immediate#P40(
'create TABLE AGNTPF1 AS
(SELECT * FROM AGNTPF WHERE START_DATE >= DEC(REPLACE(CHAR(CURRENT_DATE - 1 MONTH, ISO), ''-'', ''''), 8, 0) ) with data');
end;
Alternatively, you can use the famous q operator (here, I use the pipe symbol | to mark the beginning and end of the quoted string):
declare
ret integer;
begin
ret := dbms_hs_passthrough.execute_immediate#P40(
q'|create TABLE AGNTPF1 AS
(SELECT * FROM AGNTPF WHERE START_DATE >= DEC(REPLACE(CHAR(CURRENT_DATE - 1 MONTH, ISO), '-', ''), 8, 0) ) with data|');
end;

Declaring timestamp in postgres

I have to insert a timestamp value into a table. I am inserting values by writing an stored procedure.
This is the code to my stored procedure.
CREATE OR REPLACE FUNCTION dataInsert_Schedule() RETURNS boolean As
$$
DECLARE
i integer;
j integer;
dur integer;
tup Channel%rowtype;
BEGIN
FOR tup IN SELECT * FROM Channel
LOOP
for i in 0..6 LOOP --days
for j in 0..23 LOOP --hours
dur = round((random() * 2) + 1);
IF i + dur > 24 then
dur = 24 - i;
END IF;
INSERT INTO Schedule VALUES(tup.Channel_ID, round((random() * 999) + 1),( current_date + (integer to_char(i,'9')) )+ (interval to_char(j,'99') || ' hour'), (interval dur ||' hour'));
i = i + dur - 1;
END LOOP;
END LOOP;
END LOOP;
return true;
END
$$ LANGUAGE plpgsql;
When I write the query Select * From dataInsert_Schedule(); I got the following error :
ERROR: syntax error at or near "to_char"
LINE 1: ...d((random() * 999) + 1),( current_date + (integer to_char( $...
^
QUERY: INSERT INTO Schedule VALUES( $1 , round((random() * 999) + 1),( current_date + (integer to_char( $2 ,'9')) )+ (interval to_char( $3 ,'99') || ' hour'), (interval $4 ||' hour'))
CONTEXT: SQL statement in PL/PgSQL function "datainsert_schedule" near line 15
********** Error **********
ERROR: syntax error at or near "to_char"
SQL state: 42601
Context: SQL statement in PL/PgSQL function "datainsert_schedule" near line 15
I First tried this
INSERT INTO Schedule VALUES(tup.Channel_ID, round((random() * 999) + 1),( current_date + (integer ''||i) )+ (interval (j ||' hour')), (interval dur ||' hour'));
way of inserting, but I was getting the same kind of error.
Why I am getting this error?
And the schedule table is defined as following:
CREATE TABLE Schedule(
Channel_ID Integer REFERENCES Channel(Channel_ID),
Program_ID Integer REFERENCES Program(Program_ID),
Start_Time Timestamp NOT NULL,
Duration Interval NOT NULL,
CONSTRAINT Schedule_Key PRIMARY KEY(Channel_ID, Program_ID)
);
It works for me like this:
select (to_char(1,'99') || ' hour')::interval;
You don't need the to_char:
select (1 || ' hour')::interval;
interval
----------
01:00:00
So this would be it:
INSERT INTO Schedule
VALUES (
tup.Channel_ID,
round((random() * 999) + 1),
(current_date + i::integer) + (j || ' hour')::interval,
(dur ||' hour')::interval
)
A type name may be specified before a string constant to cast it into this type, but it applies only to constants. So integer '123' is fine but integer to_char(something) or interval column_name are not permitted, which is why your query fails.
This is explained in the SQL syntax chapter from the manual, specifically this paragraph: Constants of Other Types.
Excerpt:
A constant of an arbitrary type can be entered using any one of the
following notations:
type 'string'
'string'::type
CAST ( 'string' AS type )
and below:
The ::, CAST(), and function-call syntaxes can also be used to specify
run-time type conversions of arbitrary expressions
The point relevant to the question being that type 'string' notation is not included in the syntaxes that can accept arbitrary expressions, contrary to :: and cast().