ORACLE SQL SYSDATE and between - sql

I am trying to get a date using between SYSDATE and SYSDATE - 300.
SELECT date_entered
FROM customer_order_join
WHERE TO_CHAR(date_entered, 'YYYYMMDD') BETWEEN
TO_DATE(sysdate, 'YYYYMMDD') AND TO_DATE(sysdate, 'YYYYMMDD') - 300
I am getting the following error :
ORA-01858: a non-numeric character was found where a numeric was expected.

SYSDATE returns a DATE value. Never run TO_DATE() on a value which is already a DATE. Apart from that, BETWEEN ... AND requires the lower date first.
You can compare the DATE values directly, I guess you are looking for this:
SELECT DATE_ENTERED
FROM CUSTOMER_ORDER_JOIN
WHERE DATE_ENTERED Between SYSDATE-300 AND SYSDATE
Most likely you like to compare just the date values, without time value. Then you could use this:
SELECT DATE_ENTERED
FROM CUSTOMER_ORDER_JOIN
WHERE TRUNC(DATE_ENTERED) Between TRUNC(SYSDATE-300) AND TRUNC(SYSDATE) -- or TRUNC(SYSDATE)+1 to cover full day
Note, the query will not utilize an index on DATE_ENTERED, unless you have a function-based index on TRUNC(DATE_ENTERED). So you may prefer
SELECT DATE_ENTERED
FROM CUSTOMER_ORDER_JOIN
WHERE DATE_ENTERED >= TRUNC(SYSDATE-300)
AND DATE_ENTERED < TRUNC(SYSDATE)

There is some strange date conversions in your where clause:
To_Char(DATE_ENTERED, 'YYYYMMDD')
If the column is already a date type just use the column without any conversions and if it is a string, use TO_DATE.
TO_DATE(SYSDATE,'YYYYMMDD')
No conversion needed
TO_DATE(SYSDATE,'YYYYMMDD')-300
No conversion needed
So maybe just:
SELECT DATE_ENTERED FROM CUSTOMER_ORDER_JOIN
WHERE TRUNC(DATE_ENTERED) Between TRUNC(SYSDATE - 300) AND TRUNC(SYSDATE);

Related

Not a Valid Month - Working with Dates in Oracle

I am finding it strenuous to work with dates in my customized environment. I have a request to add a where clause which caters to specific dates but I just cannot get oracle to budge. Any ideas anyone please.
select created_date, cast(created_date as date) as created_date_cast
from mytable;
created_date created_date_cast
04-Mar-20 05.21.15.772000 AM 3/4/2020 5:21:15 AM
04-Mar-20 05.21.15.709000 AM 3/4/2020 5:21:15 AM
04-Mar-20 05.17.14.902000 AM 3/4/2020 5:14:14 AM
28-Feb-20 01.15.25.702700 AM 2/28/2020 1:15:25 AM
When I try to add a where clause the snippet blows up with the error:
select created_date, cast(created_date as date) as created_date_cast
from mytable
where cast(created_date as date) <= '02/28/2020';
ORA-01843: not a valid month
I have also tried to_date(created_date, 'MM/DD/YYYY') in the from but proves to be erroneous with:
ORA-01858: a non-numeric character was found where a numeric was expected
Firstly cast as date which converts a timestamp value to a date value, and then don't forget to add trunc() function in order to include the boundry value (date'2020-02-28' in this case) also as
where trunc(cast(created_date as date)) <= date'2020-02-28'
Demo
Don't use CAST and don't use TRUNC (as then Oracle will not be able to use an index on your column but would, instead, require a function-based index created on TRUNC(created_date)) just add a day and use a literal:
SELECT created_date
FROM mytable
WHERE created_date < DATE '2020-02-29';
or
SELECT created_date
FROM mytable
WHERE created_date < TIMESTAMP '2020-02-29 00:00:00';
or, if you want to specify the exact date then just add a day. E.g.:
SELECT created_date
FROM mytable
WHERE created_date < DATE '2020-02-28' + INTERVAL '1' DAY;
All of those options should be able to use an index on the created_date column.
I have also tried to_date(created_date, 'MM/DD/YYYY') in the from but proves to be erroneous with:
ORA-01858: a non-numeric character was found where a numeric was expected
TO_DATE( value_string, format_model ) takes strings as its arguments but CREATED_DATE is a TIMESTAMP data type and not a string so Oracle must make an implicit TIMESTAMP-to-string conversion and it does this using the NLS_TIMESTAMP_FORMAT session parameter; so your expression is effectively:
TO_DATE(
TO_CHAR(
created_date,
( SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_TIMESTAMP_FORMAT' )
),
'MM/DD/YYYY'
)
And if your NLS_TIMESTAMP_FORMAT is not MM/DD/YYYY then its highly likely that an exception will be raised (i.e. like the ORA-01858 you had).
You should never rely on implicit string conversions as any user can change their own session parameters at any time and an implicit conversion that works for one user may not work for another just because they have different parameter values (even though the queries are identical).
Use a date literal:
cast(created_date as date) <= date '2020-02-28'
I would also recommend dispensing with the cast() -- assuming that created_date is correctly stored as a date or timestamp:
created_date < (date '2020-02-28' + interval '1' day)

Filtering a dataset by date and time Oracle SQL through Power BI

I'm having trouble with filtering a date and time for anything two hours before and sooner. I tried this:
SELECT *
FROM
table
where
date >= sysdate - 1
AND
TO_DATE( Time, 'HH24:MI:SS' ) >= TO_DATE( sysdate, 'HH24:MI:SS' ) - 2
But I'm getting an inconsistent type error which is what I thought I was handling with the TO_DATE() function but I guess not.
sysdate is already a date (and time), so TO_DATE( sysdate, 'HH24:MI:SS' ) doesn't make any sense.
You didn't provide your data types for your date and time columns in table, so I'm going to assume they're both varchar2(10) with formats MM/DD/YYYY and HH24:MI:SS respectively.
I'm also going to go ahead and change your example table and column names, since they're invalid names to use in a real query.
-- example data
with my_table as (select '06/13/2019' as date_column, '09:40:34' as time_column from dual)
-- your query
SELECT *
FROM
my_table
where
to_date(date_column || ' ' || time_column, 'MM/DD/YYYY HH24:MI:SS') >= sysdate - 2/24
What I'm doing here is to combine your date and time strings into one date-time string, then converting it to an Oracle date type (actually date+time). Then we compare it to sysdate - 2/24, which says to take the current time and subtract 2/24ths of a day, which is 2 hours.
For this example, you might need to change the example data date_column and time_column values to something from the past 2 hours, depending on when you run this and what time zone you're in.

Sql Change Time in Query

I currently have the following Problem, working on an Oracle Database:
I have 2 columns of an appointment I want to read: date_from and date_to. They have both DateTime as the datatype.
I need to adjust the time of the value though (and only the time, the date should stay the same).
date_from for example contains 10.10.2017 14:21:00 as a value,
but should be changed to the "start of the day" --> 10.10.2017 00:00:00
date_to for example contains 11.10.2017 11:47:00 as a value,
but should be changed to the "end of the day" --> 10.10.2017 23:59:59
Is this somehow possible to manipulate it this way? I can not do an Update or permanent change to the data. This Format is only needed for a Gantt Diagramm, I dont have an other way to change it.
Thank you in Advance!
Yes, you can achieve that with Oracle's TO_DATE and TO_CHAR functions. It will only depend if you need the result as a DATE or as a VARCHAR. The syntax would look like this for VARCHAR output:
TO_CHAR(date_from, 'DD.MM.YY') || ' 00:00:00'
TO_CHAR(date_to, 'DD.MM.YY') || ' 23:59:59'
If you need the DATE value from this, just add the TO_DATE funtion around it:
TO_DATE((TO_CHAR(date_from, 'DD.MM.YY') || ' 00:00:00'), 'DD.MM.YY HH24:MI:SS')
TO_DATE((TO_CHAR(date_to, 'DD.MM.YY') || ' 23:59:59'), 'DD.MM.YY HH24:MI:SS')
I did not test it, but it's pretty much it.
Does this helps?
Cheers
Nikao
If you need to show the result, try this:
select to_char(date_from, 'DD.MM.YYYY') ||' 00:00:00' as date_from,
to_char(date_to, 'DD.MM.YYYY') ||' 23:59:59' as date_to
from table_name
But you may need to compare intervals. In this case, you could discarts the time using trunc function:
select *
from table_dates t,
other_table o
where trunc(o.some_date) between trunc(t.date_from) and trunc(t.date_to)
UPD: First, I did an implicit conversion of dates to string using TRUNC. But it can lead to inexpected result. Instead, explicitly use TO_CHAR with the format model you are expecting for your output and you do not need to use TRUNC. (Thank you #MT0 )
So you want to return the start and end of the day?
select trunc(start_date) as day_start, -- Strips off the time part of the date
trunc(end_date) + 1 - (1/86400) as day_end -- As above, but we add 1 day and minus 1 second
from My_Table
Also, Oracle has date formats of Date and Timestamp, no datetime
this might be some help to you:
SELECT to_char(current_timestamp,'yyyy-mm-dd hh:mm:ss') FROM dual;
SELECt trunc(current_timestamp)||' 23:59:59' FROM dual;

Getting rid of the time in a date

SELECT close_date, close_UIN, count(*) as Amount_Closed_per_employee
FROM t_return_master
where status = 'C' AND TO_DATE (close_date ,'DD-MON-YY') BETWEEN TO_DATE
('~Date From~', 'DD/MM/YYYY') AND TO_DATE('~Date To~','DD/MM/YYYY')
group by close_date, close_UIN
order by close_UIN
I have the code you see above, at the moment it displays the hours, minutes and seconds when it displays the close date, however as I am grouping by close date, I need this to go so it group by date only. Anyone any ideas how I can do this?
You can use TRUNC() on the date (in the SELECT and GROUP BY clauses) which, with just the default argument, sets the hours/minutes/seconds/milliseconds to zero.
SELECT TRUNC( close_date ) AS close_date_day,
close_UIN,
count(*) as Amount_Closed_per_employee
FROM t_return_master
where status = 'C'
AND TO_DATE (close_date ,'DD-MON-YY')
BETWEEN TO_DATE('~Date From~', 'DD/MM/YYYY')
AND TO_DATE('~Date To~','DD/MM/YYYY')
group by TRUNC( close_date ), close_UIN
order by close_UIN
The simplest way is to use the trunc() function, which by default sets the time portion of the date value to midnight:
SELECT trunc(close_date), close_UIN, ...
...
group by trunc(close_date), close_UIN
order by close_UIN
Note that you need to truncate the value in the select list and the group-by clause. The function can optionally truncate to a different precision too, like removing seconds, or going to the first day of the month, etc.:
select sysdate, trunc(sysdate), trunc(sysdate, 'SS') from dual;
SYSDATE TRUNC(SYSDATE) TRUNC(SYSDATE,'MI')
------------------- ------------------- -------------------
2015-05-01 09:37:48 2015-05-01 00:00:00 2015-05-01 09:37:00
See the docs for more info.
This is not correct:
AND TO_DATE (close_date ,'DD-MON-YY') BETWEEN TO_DATE
('~Date From~', 'DD/MM/YYYY') AND TO_DATE('~Date To~','DD/MM/YYYY')
Since close_date is already a date column you're doing an implicit conversion to a string using your NLS_DATE_FORMAT, and then an explicit conversion back to a date using 'DD-MON-YY' - which is using a two-digit year and will cause its own problems. The behaviour may vary for other users with different settings.
It looks like you're trying to do the equivalent of a trunc() to make the between cover the whole of the final day, but you won't get the year (century) you expect. And calling any function on the column will prevent any index on it being used, unless you have a matching function-based index (but using trunc() only in the select list and group by is OK).
If you want all records from the start of 'date from' to the end of 'date to' you can specify that with a range instead of 'between' - which is inclusive but might not get the result you expect depending on your NLS settings, again. Something like:
AND close_date >= TO_DATE('~Date From~', 'DD/MM/YYYY')
AND close_date < TO_DATE('~Date To~','DD/MM/YYYY') + 1
Less than midnight on the day after 'date to' is equivalent to saying up to 23:59:59 on 'date to', i.e. covering that entire day.

Using "Interval" in Oracle where "Interval" is a value from a table

I need to generate a list of values in an Oracle DB with the following columns of data:
ITEM_TYPE VARCHAR2(20)
ITEM_LAST_UPDATED DATE
ITEM_UPDATE_TOLERANCE NUMBER(1)
The only data that should be send out to the console would be items that have the date in 'ITEM_LAST_UPDATED' less than the sysdate minus the integer value within 'ITEM_UPDATE_TOLERANCE'.
So, if I wanted to just show the ones that were one hour past due, I can do:
select ITEM_TYPE from MY_TABLE
where
to_char(ITEM_LAST_UPDATED, 'DD-MON-YYYY HH24:MI')
<=
to_char(sysdate - interval '1' hour, 'DD-MON-YYYY HH24:MI');
However, rather than using the '1' in the above statement, I need to replace it with the numeric value of ITEM_UPDATE_TOLERANCE.
I tried several different versions, but all error (such as):
select ITEM_TYPE from MY_TABLE
where
to_char(ITEM_LAST_UPDATED, 'DD-MON-YYYY HH24:MI')
<=
to_char(sysdate - interval to_number(ITEM_UPDATE_TOLERANCE) hour, 'DD-MON-YYYY HH24:MI');
Why are you converting a perfect DATE column to a character value just to compare it another DATE value converted to a character column.
Simply use:
ITEM_LAST_UPDATED <= sysdate - interval '1' hour
To achieve what you want, just multiply the value:
ITEM_LAST_UPDATED <= sysdate - (interval '1' hour) * ITEM_UPDATE_TOLERANCE
There is also absolutely no need to convert a number to a number using the to_number() function.
As an alternative to #a_horse_with_no_name's interval multiplication trick, or San's division method, you can also use the numtodsinterval() function:
ITEM_LAST_UPDATED <= sysdate - numtodsinterval(ITEM_UPDATE_TOLERANCE, 'HOUR')
As an example:
select sysdate, sysdate - numtodsinterval(3, 'HOUR') from dual;
SYSDATE SYSDATE-NUMTODSINTE
------------------- -------------------
2014-03-07 19:08:27 2014-03-07 16:08:27
Well you can try using simple calculation
select ITEM_TYPE from MY_TABLE
where
ITEM_LAST_UPDATED
<=
sysdate - (ITEM_UPDATE_TOLERANCE/24);
Calculation of ITEM_UPDATE_TOLERANCE/24 will convert hours into days and then can be subtracted from sysdate.