make_date function does not exist in plpgsql - postgresql

I've got a plpgsql function. I need to take the date 5 days from today, and then divide month into "fives" to takte the start of "last five". The problem is thay make_date does not exist in the posgres version that is used on the server....
create or replace function getFirstDayOfFive()
returns timestamp with time zone as $$
declare
firstDay timestamp;
startOp timestamp;
begin
startOp = now() - interval '5 day';
SELECT
make_date(
date_part('year', startOp)::int,
date_part('month', startOp)::int,
greatest(
floor(date_part('day', startOp) / 5) * 5,
1
)::int
)
INTO firstDay;
RETURN firstDay;
end;
$$
language plpgsql;
It worked fine last week, but now I got an error when I call it
ERROR: BŁĄD: function make_date(integer, integer, integer) does not exist
LINE 2: make_date(
^
HINT: There is no function matching provided name and arguments. Maybe you should cast data.
QUERY: SELECT
make_date(
date_part('year', startOp)::int,
date_part('month', startOp)::int,
greatest(
floor(date_part('day', startOp) / 5) * 5,
1
)::int
)
CONTEXT: PL/pgSQL function "getfirstdayoffive" line 7 at wyrażenie SQL
SQL state: 42883
What happened that earlier it worked and now it gives error?
[Edit]
I found out that make_date is available from postgresQL 9.4, but on the server there is posthresQL 9.1 is there any way to do the same in this old version od DB? I'm trying to replace the make_date with something like
create or replace function getFirstDayOfFive()
returns timestamp with time zone as $$
declare
firstDay timestamp;
startOp timestamp;
begin
startOp = now() - interval '5 day';
SELECT
date to_char(startOp, 'YYYY-MM-')||to_char(greatest(
floor(date_part('day', startOp) / 5) * 5,
1
)::int)
INTO firstDay;
RETURN firstDay;
end;
$$
language plpgsql;

I think you can simplify this by simply adding the desired number of days to the start of the month. Apparently you only want a date so I would also recommend to change the return type to date
create or replace function getfirstdayoffive()
returns date
as
$$
select date_trunc('month', current_date - 5)::date
+ (greatest(floor(extract(day from current_date - 5) / 5) * 5, 1))::int - 1;
$$
language sql
stable;

Related

CREATE TABLE if not exists based on a SELECT statement

I want to create a table if it does not exists based on a select statement in PostgreSQL 9.2. When I use the below query, i get an error as mentioned below.
Query:
CREATE TABLE IF NOT EXISTS ccdb_archival.bills
SELECT *, now() AS archival_date
FROM ccdb.bills
WHERE bill_date::date >= current_date - interval '3 years' AND bill_date::date < current_date - interval '8 years';
Error:
ERROR: syntax error at or near "SELECT"
LINE 2: SELECT *, now() AS archival_date
Can someone suggest how can I achieve this.
I did get an alternate for this. I used the below mentioned code.
CREATE OR REPLACE FUNCTION ccdb_archival.ccdb_archival()
RETURNS void AS
$BODY$
BEGIN
CREATE TABLE IF NOT EXISTS ccdb_archival.bills (LIKE ccdb.bills INCLUDING ALL);
BEGIN
ALTER TABLE ccdb_archival.bills ADD COLUMN archival_date timestamp;
EXCEPTION
WHEN duplicate_column THEN RAISE NOTICE 'column archival_date already exists in ccdb_archival.bills.';
END;
INSERT INTO ccdb_archival.bills
SELECT *, now() AS archival_date
FROM ccdb.bills
WHERE bill_date::date >= current_date - interval '3 years' AND bill_date::date < current_date - interval '8 years';
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;

How to implement add_months in PostgreSQL? [duplicate]

This question already has answers here:
Calculating a date in Postgres by adding months?
(2 answers)
Closed 7 years ago.
How to implement add_months in PostgreSQL ??
Like oracle ADD_MONTHS returns the date.
Ex. ADD_MONTHS(hire_date,1)
use
hire_date + interval '1 month'
this will return exactly one month added to hire_date.
For More References on date and time functions in postgre Date time function
CREATE FUNCTION add_months(start DATE, months INT) RETURNS DATE AS
$$
SELECT (start + (months || ' months')::INTERVAL)::DATE
$$
LANGUAGE sql IMMUTABLE
In PostgreSQL you can create a function to do the job
create or replace function ADD_MONTHS(var_dte date,cnt int) returns setof date as
$$
declare
qry text;
begin
qry = format( 'select (''%s''::date + interval ''%s'')::date',var_dte,cnt||' month') ;
RETURN QUERY
EXECUTE qry;
end
$$
language plpgsql
and call this function
select ADD_MONTHS('2015-11-27',1)
Result:
add_months
date
----------
2015-12-27
in your case
select hire_date
,ADD_MONTHS(hire_date,1)
from table_name

Function Getting the right week number of year

I want to create a function to get the right week number of year.
I already posted here to find a 'native' solution, but apparently there is not.
I tryed to create funcrtion based on this mysql example
Here is the code translated to postgresql:
CREATE OR REPLACE FUNCTION week_num_year(_date date)
RETURNS integer AS
$BODY$declare
_year integer;
begin
select date_part('year',_date) into _year;
return ceil((to_char(_date,'DDD')::integer+(to_char(('01-01-'||_year)::date,'D')::integer%7-7))/7);
end;$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
But it gives wrong result, can someone help me ?
My config: PostgreSQL 9.2
If you want proper week numbers use:
select extract(week from '2012-01-01'::date);
This will produce the result 52, which is correct if you look on a calendar.
Now, if you actually want to define week numbers as "Every 7 days starting with the first day of the year" that's fine, though it doesn't match the week numbers anyone else uses and has some odd quirks:
select floor((extract(doy from '2011-01-01'::date)-1)/7)+1;
By the way, parsing date strings and hacking them up with string functions is almost always a really bad idea.
create or replace function week_num_year(_date date)
returns integer as
$body$
declare
_year date;
_week_number integer;
begin
select date_trunc('year', _date)::date into _year
;
with first_friday as (
select extract(doy from a::date) ff
from generate_series(_year, _year + 6, '1 day') s(a)
where extract(dow from a) = 5
)
select floor(
(extract(doy from _date) - (select ff from first_friday) - 1) / 7
) + 2 into _week_number
;
return _week_number
;
end;
$body$
language plpgsql immutable
You can retrieve the day of the week and also the week of the year by running:
select id,extract(DOW from test_date),extract(week from test_date), testdate,name from yourtable
What about the inbuild extract function?
SELECT extract (week from current_timestamp) FROM A_TABLE_FROM_YOUR_DB;

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.