How to add variable minutes to a given date? - sql

I have the next query (I'm using postgresql):
SELECT TIMESTAMP fecha_cita + cast((select tiempo_intervencion from cita_intervencion) as interval)
from cita;
What I'm doing here is basically taking a date like this '2001-09-28 01:00' from the 'cita' table (that's what fecha_cita is) and I want to add more time to this complete date, in this case 'tiempo_intervencion' is something like '120 minutes' but this information is in a different table called 'cita_intervencion', the problem is that since these are variables dates and times and not a fixed date, things like SELECT TIMESTAMP '2010-11-19 01:11:22' + INTERVAL '120 minutes doesn't work for me, I get errors like:
ERROR: syntax error at or near "fecha_cita"
LINE 1: SELECT TIMESTAMP fecha_cita + cast((select tiempo_intervenci...
ERROR: cannot cast type d_entero_p to interval
LINE 1: ...ct tiempo_intervencion from cita_intervencion) as interval) ...
I've looked up on google for some information on this and I was trying to follow this, but I can't find anything that can solve my problem.

You need a join and then cast the string to an interval:
SELECT c.fecha_cita, fecha_cita + ci.tiempo_intervencion::interval
from cita c
join cita_intervencion ci on c.id = ci.cita_id;
This assumes that there is some column in cita_intervencion that links that back to the cita table. If you really do not have that you can do something like this:
SELECT c.fecha_cita, fecha_cita + (select tiempo_intervencion::interval from cita_intervencion)
from cita c
But that will only work if cita_intervencion contains exactly one row.
The casting to an interval will only work if the values in tiempo_intervencion follow the rules for an interval.
You do not need the timestamp keyword for columns already defined as a timestamp that is only needed to introduce a timestamp literal (constant) value.
SELECT TIMESTAMP '2010-11-19 01:11:22' + INTERVAL '120 minutes doesn't work for me
That works if you add the missing ' for the interval literal:
SELECT TIMESTAMP '2010-11-19 01:11:22' + INTERVAL '120 minutes'

You can use:
select DATEADD(MINUTE,120,GETDATE())

Related

How to get all rows during a day with a specific column value

I have multiple rows in a table with a column named "created" that has a timestamp in the format "1309494407". I need to do a SQL query to get how many rows there are that has a certain value of column called "category" with the value of "book". Basically I need to know how many books are created every day in the database.
How is this accomplished with PostgreSQL?
My schema:
Items(id, category, created)
This is what I've tried so far:
SELECT
*
FROM
my_schema.items
WHERE
(category = 'books' AND TO_TIMESTAMP(created) < NOW() - INTERVAL '1 days')
And it doesn't work I get problem:
function to_timestamp(character varying) does not exist
Basically I need to know how many books are created every day in the database.
Your timestamp looks like a Unix epoch. If so, you can get what you want using simple arithmetic:
SELECT floor(i.created / (24 * 60 * 60)) as dy, COUNT(*)
FROM my_schema.items i
WHERE i.category = 'books'
GROUP BY dy;
If you like, you can convert it to a calendar date using:
SELECT '1970-01-01' + floor(i.created / (24 * 60 * 60)) * interval '1 day' as dy, COUNT(*)
FROM my_schema.items i
WHERE i.category = 'books'
GROUP BY dy;
What a wonder example of why Unix epoch is such a poor choice for storing dates, and a text representation of the number at that. Always store dates/timestamps with the appropriate type. If needed the epoch is easily retrieved from a date, but deriving the date from epoch is - well ugly. And actual timestamp even uglier.
If you happen to to be on version 12 you can at least capture the date in a table column itself, without having to change the code already using the existing column. Create a generated column that derives the actual date. (Guess that would make an interesting round trip, given a date derive the epoch then given the epoch derive the date).
alter table items
add created_date date generated always as
('1970-01-01'::timestamp + (created::integer/ 86400) * interval '1 day')
stored;
Now this query reduces itself to the simple and straight forward:
select i.created_date,count(*)
from my_schema.items i
where i.category = 'books'
group by i.created_date
order by i.created_date;
It also has the additional benefit of making all the Postgres date handling functions available.

SQL Invalid operation for DateTime or Interval when casting a hour/minute to an existing Timestamp

I'm trying to cast an existing Date variable as a timestamp, and add hours and minutes from another Time variable to get a final variable of the format mm/dd/yyyy hh:mm:00.
The current line of the query that errors out is:
cast(DepDt as timestamp) + cast(substr(ArrTm, 1, 2) as interval hour) + cast(substr(ArrTm, 3, 2) as interval minute) as Arrv_DTML
I can't seem to find what's wrong though. I have gotten rid of the substring functions to make sure it wasn't something wrong with that, but I can't seem to cast the ArrTm as an interval even on its own. Is it something with the format of the variables? I am running this in Teradata.
DepDt is a Date. ArrTM is a Time variable.
You can't apply substr on a Time, you must explicitly cast it to a VarChar first:
Cast(DepDt AS TIMESTAMP(0))+
+ Cast(Substr(Cast(ArrTm AS VARCHAR(8)), 1, 5) AS INTERVAL HOUR TO MINUTE)
But there's an easier way to get your result:
Cast(DepDt AS TIMESTAMP(0)) -- date to Timestamp
+ (Extract(HOUR From ArrTm) * INTERVAL '1' HOUR) -- hour to Interval
+ (Extract(MINUTE From ArrTm) * INTERVAL '1' MINUTE) -- minute to Interval

Compare date + time with timestamp

I have a table with two temporal columns. First (name is DATE) is storing the date (not including the time part) and therefor the datatype is DATE. Second column (name is TIME) is for storing the time in seconds and therefor the datatype is NUMBER.
I need to compare this two dates with a timestamp from another table. How can I calculate the date of the two columns (DATE and TIME) and compare to the timestamp of the other table?
I have tried to calculate the hours out of the time column and add it to the date column, but the output seems not correct:
SELECT to_date(date + (time/3600), 'dd-mm-yy hh24:mi:ss') FROM mytable;
The output is just the date, but not the time component.
You can use the INTERVAL DAY TO SECOND type:
SELECT your_date + NUMTODSINTERVAL(your_time_in_seconds, 'SECOND') FROM dual;
Example:
SELECT TRUNC(SYSDATE) + NUMTODSINTERVAL(39687, 'SECOND') FROM dual;
The calculated date with time is: 10-11-2013 11:01:27
This is a better idea than dividing your value by 3600 in my opinion, as you have an interval in seconds, so it feels natural to use an interval to represent your time, which can then be easily added to a column of DATE datatype.
Oracle Interval in Documentation
NUMTODSINTERVAL Function in documentation
date + (time/3600) is already a DATE, so you don't need to do to_date(). It does have the time part you added though, you just aren't displaying it. If you want to output that as a string in the format you've shown, use to_char() instead:
SELECT to_char(date + (time/3600), 'dd-mm-yy hh24:mi:ss') FROM mytable;
... except that if time is actually in seconds, you need to divide by 86400 (24x60x60), not 3600. At the moment you're relying on your client's default date format, probably NLS_DATE_FORMAT, which doesn't include the time portion from what you've said. That doesn't mean the time isn't there, it just isn't displayed.
But that is just for display. Leave it as a date, by just adding the two values, when comparing against you timestamp, e.g.
WHERE date + (time/86400) < systimestamp
Try like this,
SELECT TO_DATE('11/11/2013','dd/mm/yyyy') + 3600/60/60/24 FROM DUAL;
Your query,
SELECT date + time/60/60/24 FROM mytable;
try using to_timestamp instead of to_date

PostgreSQL: SELECT integers as DATE or TIMESTAMP

I have a table where I have multiple integer columns: year, month and day. Unfortunately, while the three should have been grouped into one DATE column from the beginning, I am now stuck and now need to view it as such. Is there a function that can do something along the lines of:
SELECT makedate(year, month, day), othercolumn FROM tablename;
or
SELECT maketimestamp(year, month, day, 0, 0), othercolumn FROM tablename;
You can
SELECT format('%s-%s-%s', "year", "month", "day")::date
FROM ...
or use date maths:
SELECT DATE '0001-01-01'
+ ("year"-1) * INTERVAL '1' YEAR
+ ("month"-1) * INTERVAL '1' MONTH
+ ("day"-1) * INTERVAL '1' DAY
FROM ...
Frankly, it's surprising that PostgreSQL doesn't offer a date-constructor like you describe. It's something I should think about writing a patch for.
In fact, a quick look at the sources shows that there's an int date2j(int y, int m, int d) function at the C level already, in src/backend/utils/adt/datetime.c. It just needs to be exposed at the SQL level with a wrapper to convert to a Datum.
OK, now here's a simple makedate extension that adds a single function implemented in C, named makedate. A pure-SQL version is also provided if you don't want to compile and install an extension. I'll submit the C function for the 9.4 commitfest; meanwhile that extension can be installed to provide a fast and simple date constructor:
regress=# SELECT makedate(2012,01,01);
makedate
------------
2012-01-01
(1 row)
PostgreSQL 9.4+
In PostgreSQL 9.4, a function was added to do just this
make_date(year int, month int, day int)
There may be a more elegant method, but this will give you a date.
select to_date(to_char(year * 10000 + month * 100 + day,'00000000'), 'yyyymmdd')
from tablename;
Try something like:
SELECT year * interval '1 year' +
month * interval '1 month' +
day * interval '1 day'
FROM tablename;

Query using two column values to create range

I have a table with a start time timestamp column and a length integer column representing minutes. I want to be able to do something like this:
SELECT * FROM table t
WHERE t.start_time + interval 't.length minutes' < '2011-10-21';
But this doesn't work. Is there any way to get a new timestamp from the two column values?
I'm running version 8.3 of postgresql
SELECT *
FROM table
WHERE (start_time + interval '1 min' * length_minutes) < '2011-10-21 0:0'::timestamp;
Notes
Simply multiply your integer with 1-minute intervals and add it to the timestamp.
It is slightly faster to compare the timestamp to a timestamp. A date would have to be cast to timestamp (automatically).
You need to cast t.length as a character and then append it... try this instead?
SELECT *
FROM table t
WHERE
t.start_time
+ cast(cast(t.length as character varying) || ' minutes' as interval)
< '2011-10-21';