psql generate_series method doesn't support concat inside - sql

The following sql code worked as expected
generate_series('2018-06-29 00:00:00','2018-06-29 23:00:00', interval '1 hour')
but when I put concat method instead of first 2 parameters it's rise an error message
generate_series(concat('2018-06-29 00:00:00', '+05'), concat('2018-06-29 23:00:00', '+05'), interval '1 hour')
The error message
function generate_series(text, text, interval) does not exist

If you concat it becomes as text data type. Hence you cannot generate series.
Below query will produce desired result
No need to write "interval". Since start and end are timestamp postgresql understands 5h and 1h are 5hours and 1hour
select
generate_series(timestamp '2018-06-29 00:00:00' + '5h',
timestamp '2018-06-29 23:00:00' + '5h',
'1h')

That is because generate_series() does not operate on strings. Convert to the right data type:
select generate_series(concat('2018-06-29 00:00:00'::text, '+05'::text)::timestamp,
concat('2018-06-29 23:00:00'::text, '+05'::text)::timestamp,
interval '1 hour'
)

No need for concat() or string operations.
If you want to add 5 hours to the start and ending timestamp, then just add that:
generate_series(timestamp '2018-06-29 00:00:00' + interval '5 hour',
timestamp '2018-06-29 23:00:00' + interval '5 hour', interval '1 hour')

Related

Select data between dates and between times of day

I want to query rows for a given time range and also filter between given times of day.
Example I want to filter for times of day between '9.00 AM' and '10.00 PM' of every date within a given time range.
My table looks like this.
This is my sample code:
SELECT *
FROM public.energy
WHERE time >= date_trunc('month', NOW() - INTERVAL '1 MONTH') AT TIME ZONE 'Asia/Bangkok'
AND time < date_trunc('MINUTE', NOW()- INTERVAL '1 MONTH') AT TIME ZONE 'Asia/Bangkok'
AND name = 'SWU0001'
ORDER BY id DESC;
I already select data between dates that I want, but I want to filter for specific times.
SELECT *
FROM public.energy
WHERE name = 'SWU0001'
AND time >= date_trunc('month' , now() AT TIME ZONE 'Asia/Bangkok' - interval '1 month') AT TIME ZONE 'Asia/Bangkok' -- !
AND time < date_trunc('minute', now() AT TIME ZONE 'Asia/Bangkok' - interval '1 month') AT TIME ZONE 'Asia/Bangkok' -- !
AND (time AT TIME ZONE 'Asia/Bangkok')::time BETWEEN '09:00' AND '22:00' -- !!!
ORDER BY id DESC;
Don't call a timestamptz column "time". The name is misleading, and it's a basic type name.
Also, to work with local time of 'Asia/Bangkok' you need to get the local time for that time zone before applying date_trunc(), and cast the adjusted value back to timestamptz at the end. Basics:
Ignoring time zones altogether in Rails and PostgreSQL

trunc(add_months(sysdate,3),'Q')-1 equivalent expression in Postgres

can anybody convert this oracle expression trunc(add_months(sysdate,3),'Q')-1) to postgresql?
Basically this expression gives you the last day of the current quarter (provided that you remove the last closing parenthese, which otherwise is a syntax error).
In postgres, you could phrase this as:
date_trunc('quarter', current_date) + interval '3 months' - interval '1 day'
This generates a timestamp value, that you can cast if you want a date (this distinction does not exist in Oracle, where a date stores the time component as well).
The Postgres equivalent of your Oracle calculation can be seen below.
select date_trunc('quarter', current_date + interval '3 month') - interval '1 day'

PostgreSQL BigInt to DateTime and Add hours to get local time

I am trying to convert the bigint value to date in PostgreSQL
I am using the below code
SELECT TO_CHAR(TO_TIMESTAMP(1564983632051/ 1000),
'YYYY-MM-DD HH24:MI:SS')
then its returning 2019-08-05 07:40:32, which is correct.
However i want to add few hours to it to get local time. Tried with the following query but its throwing an error :
SELECT TO_CHAR(TO_CHAR(TO_TIMESTAMP(1564983632051/ 1000),
'YYYY-MM-DD HH24:MI:SS') + INTERVAL '4 hour')
I do not want to use a separate query, if that's the case i can use
select (to_timestamp('2019-08-05 07:40:32', 'YYYY-MM-DD HH24:MI:SS.US') + interval '4 hour')::timestamp;
this will return the desired output.
I need both conversion and hours addition in a single query.
You should add to TIMESTAMP portion, not to portion casted to CHAR :
SELECT TO_CHAR(
TO_TIMESTAMP(1564983632051/ 1000)+ INTERVAL '4 hour',
'YYYY-MM-DD HH24:MI:SS'
)
The problem is here:
select pg_typeof(TO_CHAR(TO_TIMESTAMP(1564983632051/ 1000), 'YYYY-MM-DD HH24:MI:SS'));
pg_typeof
-----------
text
Adding an interval to a text value is not going to work.
So something like:
select TO_CHAR(TO_TIMESTAMP(1564983632051/1000) + interval '4 hour', 'YYYY-MM-DD HH24:MI:SS') ;
to_char
---------------------
2019-08-05 02:40:32
It is best to stay in a type for operations until the very end. Then apply formatting.

Not abe to declare as timestamp in postgreSQL

select *
From #####
where username in ('akhil') and between (now() ::timestamp and now() - interval '1 day'::timestamp)
Getting error in this line .
Error - cannot cast type interval to timestamp without time zone .
You don't need the second cast. You need a column name. Something like this:
select *
from #####
where username in ('akhil') and
<some date column> >= now() - interval '1 day' and
<some date column> < now();
the error is in the second cast
now() - interval '1 day'::timestamp
is interprested as.
now() - (interval '1 day')::timestamp
when you actually mean
(now() - interval '1 day')::timestamp
or possibly you mean
now()::timestamp - interval '1 day'
both are valid, but the the result you'll get when daylight saving starts or stops is different (hint interval '1 day' is the same as interval '24 hours' in the first)
There's a strong possiblity that you should actually be using timestamp with time zone for the database column.

How to get the last day of month in postgres?

How to find the last day os the month in postgres?
I have a date columns stored as numeric(18) in the format(YYYYMMDD)
I am trying it to make it date using
to_date("act_dt",'YYYYMMDD') AS "act date"
then find the last day of this date:
like this:
(select (date_trunc('MONTH',to_date("act_dt",'YYYYMMDD')) + INTERVAL '1 MONTH - 1 day')::date)
but it gives me this error:
ERROR: Interval values with month or year parts are not supported
Detail:
-----------------------------------------------
error: Interval values with month or year parts are not supported
code: 8001
context: interval months: "1"
query: 673376
location: cg_constmanager.cpp:145
process: padbmaster [pid=20937]
-----------------------------------------------
Any help?
Postgres version:
PostgreSQL 8.0.2 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3), Redshift 1.0.874
For anybody coming to this question looking for the Postgres way to do this (not using Redshift), here's how you'd do it:
SELECT (date_trunc('month', '2017-01-05'::date) + interval '1 month' - interval '1 day')::date
AS end_of_month;
Replacing the '2017-01-05' with whatever date you want to use. You can make this into a function like this:
create function end_of_month(date)
returns date as
$$
select (date_trunc('month', $1) + interval '1 month' - interval '1 day')::date;
$$ language 'sql'
immutable strict;
EDIT Postgres 11+
Pulling this out of the comments from #Gabriel, you can now combine interval expressions in one interval (which makes things a little shorter):
select (date_trunc('month', now()) + interval '1 month - 1 day')::date as end_of_month;
-- +--------------+
-- | end_of_month |
-- +--------------+
-- | 2021-11-30 |
-- +--------------+
-- (1 row)
If you're using Amazon AWS Redshift then you can use Redshift's LAST_DAY function. While Redshift is based on PostgreSQL, the LAST_DAY function is not available in PostgreSQL, for a solution for PostgreSQL see #wspurgin's answer.
https://docs.aws.amazon.com/redshift/latest/dg/r_LAST_DAY.html
LAST_DAY( { date | timestamp } )
LAST_DAY returns the date of the last day of the month that contains date. The return type is always DATE, regardless of the data type of the date argument.
For example:
SELECT LAST_DAY( TO_DATE( act_date, 'YYYYMMDD' ) )
Okay, so you've got a numeric(18) column containing numbers like 20150118. You can convert that to a date like:
to_date(your_date_column::text, 'YYYYMMDD')
From a date, you can grab the last day of the month like:
(date_trunc('month', your_date_column) +
interval '1 month' - interval '1 day')::date;
Combined, you'd get:
select (date_trunc('month', to_date(act_dt::text, 'YYYYMMDD')) +
interval '1 month' - interval '1 day')::date
from YourTable;
Example at SQL Fiddle.
date_trunc('month',current_date) + interval '1 month' - interval '1 day'
Truncating any date or timestamp to the month level will give you the first of the month containing that date. Adding a month gives you the first of the following month. Then, removing a day will give you the date of the last day of the month of the provided date.
For future searches, Redshift does not accept INTERVAL '1 month'. Instead use dateadd(month, 1, date) as documented here.
To get the end of the month use: DATEADD(DAY, -1, (DATE_TRUNC('month', DATEADD(MONTH, 1, date))))
select to_char(date_trunc('month', now() + '01 Months'::interval) - '01 Days'::interval, 'YYYYmmDD'::text)::numeric as end_period_n