Trying to create Postgres function - postgresql

In the create screen of the Postgress GUI I'm getting a syntax error at the while statement. Language is plpgsql and return type is void. TIA
enter code here
begin
declare counter integer := 1;
declare CurrentDate Date := '1/1/2018';
while CurrentDate < '1/1/2019'
loop
insert into dimCalendar select CurrentDate, EXTRACT(DOW FROM
current_date), EXTRACT(DOY FROM current_date);
CurrentDate := CurrentDate + 1;
end loop
end

Next time, try to include all the code please
Always use ISO date format, unless you have a reason not to
declare goes before begin
You're missing a semi-colon after "end loop"
Use snake_case in PostgreSQL please
create or replace function foo() returns void as $$
declare
counter integer := 1;
curr_date date := '2018-01-01';
begin
while curr_date < '2019-01-01' loop
raise notice 'curr_date: %', curr_date;
curr_date := curr_date + 1;
end loop;
end
$$ language plpgsql;

Related

PostgreSQL PgAgent syntax error at or near DECLARE

Could someone tells me what is wrong please.
I try to create a job with using PgAgent with declaring some variables. When I run this code manually, it works successfully. But when I try to put this code in job step and save it, it throws me an error.
DO $$
DECLARE
start_date date;
dates date;
d SMALLINT;
counter integer := 0;
res date[];
treshold bigint;
BEGIN
TRUNCATE ditdemo.daily;
start_date:= now();
dates := start_date;
while counter <= 14 loop
dates := dates - INTERVAL '1 DAY';
select cal.is_holiday into d from ditdemo.calendar as cal where cal.calendardate = dates;
if d=0 then
res := array_append(res,dates);
counter := counter + 1;
end if;
/*
raise notice 'dates %', dates;
raise notice 'is holiday %', d;
raise notice 'result %', res;
*/
end loop;
insert into ditdemo.daily
select
time_bucket('1 day', j."timestamp") as day,
j.account,
count(*) as cnt
from ditdemo.jrnl as j
where
cast(j."timestamp" as date) in (select unnest(res)) AND
j.account not in (select account from ditdemo.user where is_service = 1)
group by day, j.account;
SELECT
round(PERCENTILE_CONT(0.95) WITHIN GROUP(ORDER BY d.cnt))
into treshold
FROM ditdemo.daily as d;
UPDATE ditdemo.calendar
SET daily_treshold = treshold
WHERE calendardate > start_date and calendardate <=(start_date::date + interval '7 day');
END $$;
It seems like PgAgent translates your code to another format, perhaps to string or something else and then can't parse it. To understand this try to:
Delete some special symbols from your code like brackets, quotes etc
Try to understand is it error from pgAgent or PostgreSQL
Good lucK!

debugging psql - session procedure

I am trying to modify an existing sessions procedure to add cycle count.The error I am getting is
SQL Error [42601]: ERROR: syntax error at or near "END"
Position: 3587
--call transactions_packs.tep_session()
CREATE OR REPLACE PROCEDURE transactions_packs.tep_session()
LANGUAGE plpgsql
AS $procedure$
DECLARE
session "transactions_packs"."simple_sessions";
"session_toSearch" TEXT;
"end_timestamp" TIMESTAMP WITH TIME ZONE;
"energy" NUMERIC;
"charge" NUMERIC;
"duration" NUMERIC;
"cycle_count" numeric;
"f" record ;
BEGIN
cycle_count = '0';
-- go to statement fore session reset
FOR session IN SELECT * FROM "transactions_packs"."simple_sessions" WHERE "sessionDuration" IS NULL
LOOP
BEGIN
IF session."sessionType" = 0 THEN
"session_toSearch" := 'Charging';
ELSIF session."sessionType" = 1 THEN
"session_toSearch" := 'Discharging';
END IF;
-- Session_count:Start
EXECUTE FORMAT('
FOR f IN select (current' || '%s' || '), "timestamp"
FROM "transactions_packs"."basic_measurements_packs" a order by a."timestamp" desc
LOOP
BEGIN
IF AVG((current' || '%s' || '))
OVER (ORDER BY "f"."timestamp" ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) > 0.01
then cycle_count = cycle_count + 1;
END IF;
END
END LOOP;',"session_toSearch","session_toSearch")
-- get value from If and else statement to fetch records from charging and discharging col
--Session_count :End
END ;
END LOOP;
end;
$procedure$
;
where -
schema is transactions_packs
tables are -
simple_sessions
basic_measurements_packs
Please let me know if there is any part of query is which cannot be understood.
The variable "hell" sounds like useless here, try something like this :
create or replace procedure "public"."extract"(arg json)
language plpgsql as $$
begin
raise notice 'test:%', arg->'global'->>'packetType';
raise notice 'test1:%', arg-> 'transactional'->>'A';
-- freeze the input
end ;
$$;

Syntax error at or near ","

I have problems with this function and couldn't figure out how to fix it.
Create Function Quy(sdate timestamp)
returns integer as $$
declare
numbmonth integer;
quy integer;
Begin
numbmonth := Date_part('month',sdate);
If numbmonth < 4 then
quy := 1;
else if numbmonth < 7 then
quy := 2;
else if numbmonth < 10 then
quy := 3;
else quy := 4;
return quy;
END;
$$
LANGUAGE plpgsql;
This happens when I try to run the code:
ERROR: syntax error at or near ";"
LINE 16: END;
I really don't understand what is wrong with this.
Multiple syntax errors. The function would work like this:
CREATE OR REPLACE FUNCTION quy(sdate timestamp)
RETURNS integer AS
$func$
DECLARE
numbmonth integer := date_part('month', sdate);
quy integer;
BEGIN
IF numbmonth < 4 THEN
quy := 1;
ELSIF numbmonth < 7 THEN
quy := 2;
ELSIF numbmonth < 10 THEN
quy := 3;
ELSE
quy := 4;
END IF;
RETURN quy;
END
$func$ LANGUAGE plpgsql;
Consult the manual for the basic syntax of IF.
But that's much ado about nothing. To get the quarter of the year use the field specifier QUARTER with date_part() or EXTRACT() in a simple expression:
EXTRACT(QUARTER FROM $timestamp)
EXTRACT is the standard SQL equivalent of date_part().
Either returns double precision, so cast to integer if you need that (::int).
If you still need a function:
CREATE OR REPLACE FUNCTION quy(sdate timestamp)
RETURNS int LANGUAGE sql IMMUTABLE AS
'SELECT EXTRACT(QUARTER FROM $1)::int';
$1 is the reference to the 1st function parameter. Equivalent to sdate in the example. $-notation works in any version of Postgres, while named parameter references in SQL functions were only introduced with Postgres 9.2. See:
PLPGSQL Function to Calculate Bearing
dbfiddle here

How to return results from a loop in plpgsql?

I want to see the result displaying dates like this
"2001-01-01 00:00:00+05:30"
"2001-01-02 00:00:00+05:30"
"2001-01-03 00:00:00+05:30"
"2001-01-04 00:00:00+05:30"
"2001-01-05 00:00:00+05:30"
"2001-01-06 00:00:00+05:30"
"2001-01-07 00:00:00+05:30"
so on...
but iam getting error
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function insert_date_dimension(date) line 12 at SQL statement
can you tell me what is the issue
function i created
create or replace function insert_date_dimension("Date" date)
returns text as
$$
Declare dat date;
start_date date;
end_date date;
Begin
start_date:='2016/01/01';
end_date:='2016/12/31';
while start_date<=end_date
loop
select start_date;
start_date:=start_date+ interval '1 day';
End loop;
return start_date;
end;
$$
LANGUAGE 'plpgsql';
can you tell me what is the issue with this function i was not able to execute it.I want to take all the column in select statment..please tell me create or replace function insert_date_dimension("date" date)
returns setof date as $$
declare
dat date;
start_date date;
end_date date;
begin
start_date := '2016/01/01';
end_date := '2016/12/31';
while start_date <= end_date loop
--return next start_date;
select start_date,date_part('week',start_date),date_part('quarter',start_date),to_char(start_date, 'day'),to_char(start_date, 'month'),
extract(year from current_date),extract(month from current_date);
start_date:= start_date + interval '1 day';
end loop;
end;
$$ language plpgsql;
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function insert_date_dimension(date) line 11 at SQL statement
********** Error **********
No need for a user defined function. Just use generate_series:
select generate_series('2016/01/01'::date, '2016/12/31', '1 day');
But if you are just fiddling with plpgsql then return next a setof date
create or replace function insert_date_dimension("date" date)
returns setof date as $$
declare
dat date;
start_date date;
end_date date;
begin
start_date := '2016/01/01';
end_date := '2016/12/31';
while start_date <= end_date loop
return next start_date;
start_date := start_date + interval '1 day';
end loop;
end;
$$ language plpgsql;
plpgsql is an identifier. Do not quote it.

Syntax error in declaration of PL/pgSQL function

Can anyone help me with this procedure? It's a pretty simple one, just want to insert some data into a table, but pgAdmin is giving me some errors.
This is the procedure code:
CREATE OR REPLACE FUNCTION FILL_INVOICE2(IN_NUM integer)
RETURNS void AS
DECLARE
counter numeric := 0;
BEGIN
IF in_num > 1 THEN
WHILE counter < 10
LOOP
INSERT INTO INVOICE(ID,INVOICE_ID,SUBSCRIBER_ID,AMOUNT,INVOICE_DATE,RECORD_DATE,INVOICE_TYPE,REST_TO_PAY,DESCRIPTION,INVOICE_REFERENCE)
VALUES(counter,counter,counter,100,current_date,current_date,1,100,'Telco services',1111);
counter := counter + 1;
RAISE NOTICE 'The counter is %', counter;
END LOOP;
END IF;
RETURN;
END;
Error is:
ERROR: syntax error at or near "DECLARE counter numeric"
LINE 3: DECLARE
^
********** Error **********
ERROR: syntax error at or near "DECLARE counter numeric"
SQL state: 42601
Character: 75"
This would work:
CREATE OR REPLACE FUNCTION fill_invoice2(in_num integer)
RETURNS void AS
$func$
DECLARE
counter numeric := 0;
BEGIN
IF in_num > 1 THEN
WHILE counter < 10
LOOP
INSERT INTO invoice(ID,INVOICE_ID,SUBSCRIBER_ID,AMOUNT,INVOICE_DATE,RECORD_DATE
,INVOICE_TYPE,REST_TO_PAY,DESCRIPTION,INVOICE_REFERENCE)
VALUES(counter,counter,counter,100,current_date,current_date
,1,100,'Telco services',1111);
counter := counter + 1;
RAISE NOTICE 'The counter is %', counter;
END LOOP;
END IF;
END
$func$ LANGUAGE plpgsql;
Major points
Missing language declaration.
Missing quotes around function body. Preferrably, use dollar-quoting - like #Eelke advised. Details:
Insert text with single quotes in PostgreSQL
But the whole function looks needlessly expensive.
Use a single INSERT based on generate_series() to replace the expensive loop with inserts per row. Optionally, you can wrap it in a function. Example with simple SQL function:
CREATE OR REPLACE FUNCTION fill_invoice2(in_num integer)
RETURNS void AS
$func$
INSERT INTO invoice(ID,INVOICE_ID,SUBSCRIBER_ID,AMOUNT,INVOICE_DATE,RECORD_DATE
,INVOICE_TYPE,REST_TO_PAY,DESCRIPTION,INVOICE_REFERENCE)
SELECT g,g,g,100,current_date,current_date,1,100,'Telco services',1111
FROM generate_series(0,10) g
WHERE $1 > 1;
$func$ LANGUAGE sql;
Does the same as your original.
I would also consider column defaults for some of your columns. For instance:
ALTER TABLE invoice
ALTER COLUMN invoice_date SET DEFAULT current_date
, ALTER COLUMN record_date SET DEFAULT current_date;
Details:
converting mysql scripts to postgresql script
Then just don't mention those column in the INSERT statement and defaults are filled in automatically.
The body should be passed as a string
CREATE OR REPLACE FUNCTION FILL_INVOICE2(IN_NUM integer) RETURNS void AS
$$
DECLARE
counter numeric := 0;
BEGIN
IF in_num > 1 THEN
WHILE counter < 10 LOOP
INSERT INTOI NVOICE(ID,INVOICE_ID,SUBSCRIBER_ID,AMOUNT,INVOICE_DATE,
RECORD_DATE,INVOICE_TYPE,REST_TO_PAY,DESCRIPTION,INVOICE_REFERENCE)
VALUES(counter,counter,counter,100,current_date,current_date,1,100,
'Telco services',1111);
counter := counter + 1;
RAISE NOTICE 'The counter is %', counter;
END LOOP;
END IF;
RETURN;
END;
$$
You can use $$ to mark the beginning en end of a multiline string.