Oracle SQL - select query with where condition greater than certain moment defined in a timestamp column - sql

I have a table where there is a column, report_time, whose type is timestamp. A value of it looks like "25-May-20 05.03.20.12000 PM", now I want to filter out all rows whose report_time is greater than or equal to that moment, a pseudo where clause looks like:
where report_time >= to_timestamp("25-May-20 05.03.20.12000 PM", "DD-MON-YY HH.MI.SS.FF PM")
somehow I failed to get it work, even after googling for quite some time.
Please help.

I think the idea is ok with this syntax:
report_time >= to_timestamp('25-May-20 05.03.20.12000 PM', 'DD-MON-YY HH.MI.SS.FF PM')

Related

How can i change my timestamp date in PGadmin?

i changed my datefield to timestamp in PGadmin but now all the fields have '2020-04-24 00:00:00'.
But i want that the time of all the fields have the following value '2020-04-24 12:00:00' so instead that all my field values have 00:00:00 they have 12:00:00. How can i fix this?
This works...
update table
set date = date + interval '12 hour';

Get date and time from date column in oracle

I inserted date and time in database, now when trying to retrieve date and time both from database only getting time part.
I tried insert date using TO_DATE('08/13/2019 09:10:03', 'MM/DD/YYYY HH24:MI:SS') into 'Time' col. Now trying to get date from table using TO_DATE(Time, 'DD/MON/RR HH24:MI:SS'), but only getting date part. My database nls date format is "DD/MON/RR". 'Time' col is date type and I'm using oracle 10g xe.
I can get date and time using TO_CHAR(Time, 'DD/MON/RR HH24:MI:SS') but as I need to use this in comparison operation like below:
select TO_CHAR(Time,'DD/MON/RR HH24:MI:SS') from Table where (TO_CHAR(Time, 'DD/MON/RR HH24:MI:SS') <= TO_DATE('08/07/2019 10:13:52', 'MM/DD/YYYY HH24:MI:SS'))
it gives this error 'ORA-01830: date format picture ends before converting entire input string'. Also tried to use TO_DATE(TO_CHAR(Time, 'DD/MON/RR HH24:MI:SS')), still it gives only time part. Should I use TIMESTAMP datatype for 'Time' col?
I want to get date and time from table where i can use them in comparison operation.
Date need not be converted into date again.
You can simply write your query like this:
SELECT
TIME -- use to_char for formatting the output date
FROM Table
WHERE
TIME <= TO_DATE('08/07/2019 10:13:52', 'MM/DD/YYYY HH24:MI:SS')
Cheers!!

Using TO_DATE() with AM/PM Formatting

I am trying to select some dates from a table where the format of the dates is like this:
14-APR-14 10.35.00.0000000000 AM
01-NOV-16 02.43.00.0000000000 PM
Note that the dates can be either AM or PM, but when I try to do a simple SELECT from the table such as:
SELECT * FROM MyTable
WHERE TO_DATE(MyDate, 'DD-MON-YYYY HH:MI:SS AM') > '31-DEC-2016 08:00:00 AM';
I get the error:
ORA-01855: AM/A.M. or PM/P.M. required
I've been trying to get this work for some time but with no luck. Any help here would be appreciated.
Several problems.
Your inputs are obviously strings, since they have ten decimal places and timestamps in Oracle have at most 9. Then, strings with fractions of a second can't be converted to a date with to_date - you need to use to_timestamp or else you need to remove all the fractional parts. In the solution below I only remove the last (the tenth) decimal, since you may have non-zero fractional parts in the table - although not in the sample you posted.
Then, your format mask has yyyy but your inputs have only two digits for the year (which probably means 93 means 1993 and not 2093, so the correct thing to use would be rr rather than yy). And you use : in the format mask where your inputs use .
Finally, don't even compare dates in string format: in string comparisons, 01-JAN-2015 is before 20-NOV-2013.
You probably want something like this:
select mydate
from (
select '14-APR-14 10.35.00.0000000000 AM' as mydate from dual
union all
select '01-NOV-16 02.43.00.0000000000 PM' from dual
) mytable
where to_timestamp(substr(mydate, 1, 28) || substr(mydate, -3), 'dd-MON-rr hh.mi.ss.ff AM')
> to_timestamp('31-DEC-2016 08:00:00 AM', 'dd-MON-yyyy hh:mi:ss AM');
This query compiles correctly, and it produces no rows in the output (for obvious reasons).
NOTE: In a comment you (the OP) say the mydate field is a timestamp(6) datatype. Hard to believe (you show ten decimal places), but if indeed it is a timestamp or date, then you don't need to wrap it within any to_timestamp or to_date function, it should stand alone in the left-hand side of the inequality.
From your comment:
It's actually a timestamp; not a string. Timestamp(6) to be precise
You can just use a TIMESTAMP literal:
SELECT *
FROM MyTable
WHERE MyDate > TIMESTAMP '2016-12-31 08:00:00';

Comparing clock times in SQL (Oracle)

I'm currently working on a table in Oracle database where there are time values stored in AM/PM format. By default, the times are a VARCHAR2 datatype so I have been converting them using the to_date function.
What I'm doing is comparing two different times within the table and running a query which should return the results for all times contained within that interval. The interval is acquired by using the between condition. Here is an example:
SELECT TIME
FROM TIME_TABLE
WHERE to_date(TIME,'HH:MI:SS PM') between
to_date('04:00:00 PM', 'HH:MI:SS PM') and
to_date('08:00:00 PM', 'HH:MI:SS PM');
The problem is that when you do not declare the date using the to_date function, it will automatically default to the 1st of the current month. Thus, if I wanted to get all the results from 11:59 PM to 12:00 AM I will get incorrect results.
Basically, I want to calculate the time interval in a manner where it loops instead of going only in one direction as it does naturally. Is there a way to accomplish this?
The biggest problem here is that as you add more data things will get slower and slower. It's difficult for an index to be efficiently used when you are calling a function on the field itself. It will have to scan the entire table to satisfy the query. There are three ways to avoid this:
Don't store dates or times as strings. Use the correct field type. This is the best approach.
Compare using strings instead of converting first. This will only work if you have guaranteed lexicographic ordering. You can do this with 24-hour times, but not with 12-hour times, because AM/PM gets in the way.
As Barett enlightened me in comments, Oracle has the concept of Function-Based Indexes. You could create one that pre-computes the results of to_date, such that when you use it in the query that it has an index to work against. There are several disadvantages though, so if you take this approach, I suggest you consider the consequences carefully.
With regard to the question about looping over midnight on a time-only value, the general algorithm is as follows:
Is the start-of-range value <= the end-of-range value?
If yes, then the return true if the test value is >= the start-of-range and < the end-of-range. Else return false.
If no, then return true if the test value is >= the start-of-range or < the end-of-range. Else return false.
There's no need to use :59, or any other value of the sort. Doing so can get in the way of other things, such as taking the duration of the range or testing a value like :59.5.
Not really. You'll need to add some logic for detecting a "loop" in your between criteria. If there is a loop (endRange < startRange), then the criteria should be:
to_char(to_date(TIME,'HH:MI:SS PM'),'HH24:MI:SS') >= '08:00:00' // endRange
OR to_char(to_date(TIME,'HH:MI:SS PM'),'HH24:MI:SS') <= '04:00:00' // startRange
On a side note, I reiterate wolφi's suggestion to use 24 hour time. Otherwise you'll have AM/PM problems too.
Can't you convert from an am/pm varchar to a 24h varchar and compare that one with BETWEEN?
SELECT TIME
FROM TIME_TABLE
WHERE to_char(to_date(TIME,'HH:MI:SS PM'),'HH24:MI:SS')
BETWEEN '04:00:00' AND '05:00:00';
You can test if the second time is 'earlier' than the first one, and adjust it to the following day if it is. you need to adjust the table time in the same way. Using CTEs just so you don't have to repeat the string values and conversions:
WITH R AS (
SELECT to_date('11:59:00 PM', 'HH:MI:SS PM') start_t,
to_date('12:00:00 AM', 'HH:MI:SS PM') end_t
FROM DUAL
),
T AS (
SELECT to_date(TIME,'HH:MI:SS PM') AS TIME
FROM TIME_TABLE
)
SELECT to_char(TIME, 'HH:MI:SS PM')
FROM R
JOIN T
ON T.time + case when T.time < R.start_t then 1 else 0 end
between R.start_t and
R.end_t + case when R.end_t < R.start_t then 1 else 0 end
ORDER BY T.time + case when T.time < R.start_t then 1 else 0 end;
Which isn't very pleasant.
SQL Fiddle demo.
Hopefully this is a small table and you won't see the performance issues Matt Johnson referred to...
You could avoid that by generating all possible times in your range and comparing those with the real table as strings:
WITH R AS (
SELECT to_date('11:10:00 PM', 'HH:MI:SS PM') start_t,
to_date('12:30:00 AM', 'HH:MI:SS PM') end_t
FROM DUAL
),
T AS (
SELECT level AS rn,
to_char(start_t
+ numtodsinterval(level - 1, 'SECOND'),
'HH:MI:SS PM') AS time
FROM R
CONNECT BY level <= 86400 *
(end_t + case when end_t < start_t then 1 else 0 end - start_t)
)
SELECT TT.time
FROM T
JOIN TIME_TABLE TT
ON TT.time = T.time
ORDER BY T.rn;
SQL Fiddle.
The first CTE just stops you repeating the string again. The second uses the first as a base and uses a CONNECT BY to find all the times in between, adding the number of seconds between the start and (adjusted) second string times. That wraps to the next day, but it doesn't matter as it's converted back to a string and loses the date part; and that string is then used as the filter for your real table.
You'd have the same issues with 24-hour time, since there is still no date portion, but it might make the logic a bit easier to follow. It's so long since I've done anything with 12-hour times that it's very hard to type '12' for midnight...

How to convert timestamps' timezones in order to compare them in Oracle DB?

We are using Oracle 11g and we have a table with a timestamp column which doesn't contain the timezone (simply defined as TIMESTAMP). The timezone is written in a different column.
I want to be able to use the 'max' function while taking the timezone into account.
There's probably a function to convert timezones easily and I just don't know it.
I want to be able to do something like this:
SELECT max(covert_to_timezone(my_timestamp, my_timezone, 'GMT')) FROM my_table
How can I do that?
==================
Solution: According to Ajith Sasidharan's answer:
SELECT max(from_tz(my_timestamp, my_timezone) at time zone '0:00') FROM my_table
Update: If you want to compare dates, simply use 'cast':
SELECT max(from_tz(cast(my_date as timestamp), my_timezone) at time zone '0:00') FROM my_table
Btw, now I got 'ORA 01878' errors, meaning our table contains invalid times (DST shit).
I guess you want a function like this ::
select to_char((from_tz(to_timestamp(to_char(DATABASE_DATE, 'YYYY-MM-DD HH:MI:SS PM'), 'YYYY-MM-DD HH:MI:SS PM') ,'America/New_York')
at time zone 'America/Los_Angeles'),'YYYY-MM-DD HH:MI:SS PM TZD') as localtime
from table