how can we declare a variable in cursor in postgresql - postgresql

I want to store the result of fetch into a variable how we can do that in postgresql?
I also tried by creating a function it isn't working
code :
begin work;
DECLARE
cur_films CURSOR
FOR select CURRENT_DATE + i date_
FROM generate_series(date '2019-11-11'- CURRENT_DATE, date '2019-11-15' - CURRENT_DATE ) i;
fetch forward 2 from cur_films;
close cur_films;
commit work;

If you want to pass all values generated by your query to a function or procedure, you can aggregate everything into an array, then pass that array to the function:
DECLARE
l_dates date[];
begin
select array_agg(g.dt::date)
into l_dates
from generate_series(date '2019-11-11', date '2019-11-15', interval '1 day') as g(dt);
perform your_function(l_dates);
end;
But you wouldn't need PL/pgSQL for that. This can also be done in plain SQL:
with input as (
select array_agg(g.dt::date) as dates
from generate_series(date '2019-11-11', date '2019-11-15', interval '1 day') as g(dt)
)
select *
from your_function((select dates from input));

Related

Postgresql function with values (from another table) as arguments

I can't figure out how to call a function with inputs specified from another table.
Let us assume the following function is being used to create a time interval:
create or replace function interval_generator(dt_start timestamp with TIME ZONE,
dt_end timestamp with TIME ZONE,
round_interval INTERVAL)
returns TABLE(time_start timestamp with TIME ZONE,
time_end timestamp with TIME ZONE) as $$
BEGIN
return query
SELECT
(n) time_start,
(n + round_interval) time_end
FROM generate_series(date_trunc('minute', dt_start), dt_end, round_interval) n;
END
$$
LANGUAGE 'plpgsql';
Let us create a dummy table for the minimal example:
DROP TABLE IF EXISTS lookup;
CREATE TEMP TABLE lookup
as
select *
from (
VALUES
('2017-08-17 04:00:00.000'::timestamp),
('2017-08-17 05:00:00.000'::timestamp),
('2017-08-18 06:00:00.000'::timestamp)
) as t (datetime);
Now my attempt is as follows:
select interval_generator(
SELECT datetime FROM lookup Order By datetime limit 1,
SELECT datetime FROM lookup Order By datetime Desc limit 1,
'1 hours'::interval
);
and it just yields the generic error ERROR: syntax error at or near "SELECT"
Enclose the SELECT statements in parentheses to make them expressions like this:
select * from interval_generator(
(SELECT datetime FROM lookup Order By datetime limit 1),
(SELECT datetime FROM lookup Order By datetime Desc limit 1),
'1 hours'::interval
);
Please note that
SELECT datetime FROM lookup Order By datetime limit 1
is exactly
SELECT min(datetime) FROM lookup
which seems to me better readable. As the function body of interval_generator comprises of a single SQL query why don't you make it a plain SQL function instead of pl/pgsql?
<your-function-declaration> as $$
SELECT
(n) time_start,
(n + round_interval) time_end
FROM generate_series(date_trunc('minute', dt_start), dt_end, round_interval) n;
$$
LANGUAGE 'sql';

How can i create n columns in postgresql?

I am trying to write a function that returns random start time (it must be between now and a week long) and an endtime. I wrote this function:
CREATE OR REPLACE FUNCTION random_start_end_time(n integer)
RETURNS TABLE (startime TIMESTAMP WITH TIME ZONE, endtime TIMESTAMP WITH TIME ZONE)
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
RETURN QUERY
SELECT NOW() + (random() * (NOW()+'7 days' - NOW())) as startime;
SELECT NOW() + (random() * (NOW()+'7 days' - NOW())) as endtime;
END;
$BODY$
I can't find out how to generate multiple columns. For example I want n=100 columns of random start time and end time to be generated.
In general I can't understand how I can fill an empty table (with this function I am going to fill a table later).
Any thoughts would be valuable.
Thank you.
Use RETURN NEXT to add a row to the result set of a table function and RETURN to end the function execution. You also have to decide if you want a function that returns two columns or two rows. Your case looks like you want to do something like:
CREATE OR REPLACE FUNCTION random_start_end_time(
OUT starttime TIMESTAMP WITH TIME ZONE,
OUT endtime TIMESTAMP WITH TIME ZONE
) RETURNS record
LANGUAGE sql AS
$BODY$
WITH start AS (
SELECT current_timestamp + random() * INTERVAL '7 days' as starttime
)
SELECT starttime,
starttime + random() * INTERVAL '7 days' as endtime
FROM start;
$BODY$;
Call it like
SELECT * FROM random_start_end_time();
If you really want to return several rows, that would be
CREATE OR REPLACE FUNCTION random_start_end_time()
RETURNS SETOF timestamp with time zone
LANGUAGE plpgsql AS
$BODY$
BEGIN
RETURN NEXT current_timestamp + random() * INTERVAL '7 days';
RETURN NEXT current_timestamp + random() * INTERVAL '7 days';
RETURN; /* end the function */
END;
$BODY$;

What is the difference between INTERVAL '0 days' and '0 days'::INTERVAL in postgres

I am trying to create a basic table with a list of dates in psql using a loop. The code is shown below
DO $$
DECLARE counter INTEGER :=0;
date_interval VARCHAR(250) :='0 DAYS';
BEGIN
DROP TABLE IF EXISTS temp_dates;
CREATE TABLE temp_dates (
date DATE
);
WHILE counter < 12 LOOP
date_interval := counter || ' DAYS';
INSERT INTO temp_dates
--SELECT DATE_TRUNC('DAYS', CURRENT_DATE) - date_interval :: INTERVAL;
SELECT (DATE_TRUNC('DAYS', CURRENT_DATE)) - (INTERVAL date_interval);
counter := counter + 1;
END LOOP;
END $$;
In the above query
SELECT DATE_TRUNC('DAYS', CURRENT_DATE) - date_interval :: INTERVAL;
works. But the following does not work
SELECT (DATE_TRUNC('DAYS', CURRENT_DATE)) - (INTERVAL date_interval);
Basically the only difference date_interval :: INTERVAL vs INTERVAL date_interval
But it works when I directly do something like INTERVAL '2 days' but it fails when I use a variable.
So my question is two fold
What is the difference between INTERVAL '2 days' and '2 days'::INTERVAL. From what I understand both are typecasting.
Why does INTERVAL '2 days' work but it fails when using a variable
I am sure I am missing something fairly obvious when it comes to escaping quotation marks but I am not sure. Any help would be greatly appreciated.
As the documentation states clearly, the syntax
INTERVAL '0 days'
is for constants, that is, the string has to be a literal.
It is not a syntax for type casts like '0 days'::interval, which allow you to change the type of an arbitrary expression.

LAST_DAY function in postgres

Is there any function(s) in postgres equivalent to Oracle function LAST_DAY().
I need to get last day in postgres (including month and year)
Well, In postgres, it seems there's no such function equivalent to LAST_DAY() available in oracle.
If you need to, you can have your own in the following ways as a
Select Query
SELECT (date_trunc('MONTH', now()) + INTERVAL '1 MONTH - 1 day')::date;
plsql Function
CREATE OR REPLACE FUNCTION last_day(date)
RETURNS date AS
$$
SELECT (date_trunc('MONTH', $1) + INTERVAL '1 MONTH - 1 day')::date;
$$ LANGUAGE 'sql'
IMMUTABLE STRICT;
Hope this helps.
create or replace funCtion last_day(fromdt anyelement)
returns date as
$BODY$
SELECT (date_trunc('MONTH', cast(fromdt as date)) + INTERVAL '1 MONTH - 1 day')::date;
$BODY$
LANGUAGE sql VOLATILE
COST 100;
ALTER FUNCTION last_day(anyelement)
OWNER TO postgres;

PostgreSQL: month := interval '30 days';

Trying to delete records older than 1 month from 2 tables, where 1 references the "id" column in another:
create or replace function quincytrack_clean()
returns void as $BODY$
begin
month := interval '30 days';
delete from hide_id
where id in
(select id from quincytrack
where age(QDATETIME) > month);
delete from quincytrack
where age(QDATETIME) > month;
end;
$BODY$ language plpgsql;
but this fails with:
ERROR: syntax error at or near "month"
LINE 1: month := interval '30 days'
^
QUERY: month := interval '30 days'
CONTEXT: SQL statement in PL/PgSQL function "quincytrack_clean" near line 2
I'm reading the doc, but don't understand what's wrong with my declaration...
You need to declare the variable 'month', viz.:
declare
month interval;
begin
month := interval '30 days';
end;
Also, you might want to re-examine your "where" criteria. If QDATETIME is an indexed column, I don't think it will use the index, whereas QDATETIME < (now() - month) would.
You need to declare the variable before you can use it.
...
DECLARE
month INTERVAL;
BEGIN
month := interval '30 days';
...
But I would avoid using variable names that are reserved words or internal function names.