FOR loop over a date range in Postgres - postgresql

In one of my functions in Postgres, I am trying to loop over a range of dates using the following code:
FOR timesheet_date IN select generate_series('2012-11-24'::date,'2012-12-03','1 day'::interval)::date LOOP
//My code goes here
END LOOP;
But I am getting an error
Now as am getting dates, I think it is not a record variable and hence the error.
But, how can I loop through a date range ? I am very new to Postgres actually.

DO $$
declare
dt record;
begin
FOR dt IN SELECT generate_series('2023-02-10'::date, '2023-02-15'::date, '1 day'::interval) LOOP
RAISE NOTICE 'Processing date: %', dt.generate_series;
END LOOP;
end; $$

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!

Use Extract date in Postgresql if stament

I am trying to do something similar to below MSSQL code in postgresql but i am getting error.
MSSQL code
IF (YEAR(GETDATE()) ='2020')
SELECT 1
ELSE SELECT 2
Postgres CODE
CREATE PROCEDURE PROCNAME(
DATEVAR timestamp
)
AS $BODY$
DECLARE
BEGIN
if (Extract (YEAR FROM TIMESTAMP DATEVAR) ='2020') THEN
DO SOMETHING;
ELSE DO SOMETHING ELSE;
END IF ;
$BODY$;
ERROR: syntax error at or near "DATEVAR"
Remove the timestamp prefix it is only required if you want to refer to a constant.
And numbers should be compared to numbers, not to strings.
CREATE PROCEDURE PROCNAME(
DATEVAR timestamp
)
AS $BODY$
DECLARE
BEGIN
if Extract (YEAR FROM DATEVAR) = 2020 THEN
DO SOMETHING;
ELSE DO SOMETHING ELSE;
END IF;
$BODY$;

PL/pgSQL Loops Indefinitely

I want to loop between two dates but my PL/pgSQL code goes into indefinite loop. I think I'm missing something here.
do $$
declare
the_dates date;
begin
select gs from generate_series('2019-11-01'::date, '2012-11-30', '1 day') as gs into the_dates;
loop
raise notice '%', the_dates;
end loop;
end
$$
How should I loop between these 2 dates?
You appear to be confused as to the syntax for loops.
What you have here are two separate things:
A query that select zero rows (because you have your dates backwards) into a date variable.
A loop with no limits that will raise a notice forever.
https://www.postgresql.org/docs/current/plpgsql-control-structures.html#PLPGSQL-RECORDS-ITERATING
You are not looping over the result of the SELECT statement.
If you want to loop over the result of a query you need to use for record in select ...
do $$
declare
l_date_row record;
begin
for l_date_row in select gs
from generate_series('2012-11-30'::date, '2019-11-01'::date, '1 day') as gs
raise notice '%', l_date_row.gs;
end loop;
end
$$

Postgresql 9.5 Performance degradation when updating JSON field using jsonb_set

I have a performance problem when using jsonb_set to replace values of a jsonb field.
It seems that every time the values are replaced in the JSONB expression the time updating the field increases.
This is my test table:
CREATE TABLE IF NOT EXISTS TEMP_package_var(
id VARCHAR,
val jsonb
);
My test function is:
create or replace function set_package_var_any(package_name text, var_name text, var_subname text, var_value anyelement) returns VOID as $func$
DECLARE
wk_var jsonb;
wk_mainvar jsonb;
wk_newvar jsonb;
wk_name text := lower(var_name);
wk_subname text := lower(var_subname);
start_at timestamp;
end_at timestamp;
BEGIN
select val from TEMP_package_var INTO wk_var WHERE id = lower(package_name);
if not found then
insert into TEMP_package_var(id, val) values(lower(package_name),jsonb_build_object(wk_name, jsonb_build_object(wk_subname, var_value)));
return;
end if;
wk_subname := var_name || ',' || wk_subname;
start_at := clock_timestamp();
UPDATE TEMP_package_var SET val = jsonb_set(wk_var, string_to_array(wk_subname,','), to_jsonb(var_value), true) WHERE id = lower(package_name);
end_at := clock_timestamp();
raise notice 'UPDATE Time__________________________________________: % - [%]', end_at - start_at, var_value;
END;
$func$
LANGUAGE PLPGSQL
SECURITY DEFINER;
And my main function is:
CREATE OR REPLACE FUNCTION pkgvar_set_test(loops bigint, rerun bigint) returns void as $body$
declare
start_at timestamp;
end_at timestamp;
begin
start_at := clock_timestamp();
for ix0 in 1 .. rerun loop
for ix in 1 .. loops loop
perform set_package_var_any('package_name', 'var_name', 'var_name_'||to_char(ix,'FM00000'), 'var_value_'||to_char(ix0,'FM00000')||'_'||to_char(ix,'FM00000'));
end loop;
end loop;
end_at := clock_timestamp();
raise notice 'time is %', end_at - start_at;
end;
$body$
LANGUAGE PLPGSQL
SECURITY DEFINER;
Then I execute the main function several times.
The test looks like this:
select pkgvar_set_test(2,2);
This create the following JSONB row:
{"var_name": {"var_name_00001": "var_value_00001_00001", "var_name_00002": "var_value_00001_00002"}}
And then replaces the values:
{"var_name": {"var_name_00001": "var_value_00002_00001", "var_name_00002": "var_value_00002_00002"}}
But when doing the same test with more records
First time:
select pkgvar_set_test(50,50);
NOTICE: time is 00:00:00.667468
Second time:
select pkgvar_set_test(50,50);
NOTICE: time is 00:00:01.348275
Third time:
select pkgvar_set_test(50,50);
NOTICE: time is 00:00:01.920818
And so on, as you can see replacing is getting slower and slower.
I understand the difference between the first loop and the second loop, but what I cannot figure it out is why the value increases with the number of executions.
Can somebody help me out?
Postgresql: 9.5.2
OS: Centos 7.1
Thank you

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.