Retrieve data within a date range in Oracle - sql

I have a table tbldeptdivision as follows:
ID DEPTID DIVISIONID FROMDATE TODATE REMARKS
--- ------- ----------- ----------- ----------- --------
21 21 5 31-AUG-99 01-JAN-80 NULL
I have the query
select *
from tbldeptdivision
where deptid = 21
and trunc(sysdate) between to_date(fromdate,'dd-Mon-yyyy')
and to_date(todate,'dd-mon-yyyy');
It returns me no value. Can anybody say why? '31-AUG-99' is actually '31-AUG-1999' and '01-JAN-80' is actually '01-JAN-2080'. What will be the exact query?

Assume FROMDATE/TODATE datatype is varchar2 then when you do to_date;
select to_date('01-JAN-80','dd-mon-yyyy') from dual;
OutPut: January, 01 0080 00:00:00
So it wont be '01-JAN-2080' but '01-JAN-0080'
Even if FROMDATE/TODATE datatype is date tusing to_date is not a good idea;
create table t(c date);
insert into t select sysdate from dual;
select c, to_date(c,'dd-mon-yyyy') from t;
OutPut:
C TO_DATE(C,'DD-MON-YYYY')
August, 25 2015 10:55:36 August, 25 0015 00:00:00
Still the year is 0015 not 2015.
If your columns datatype is date then use trunc to get thedate portiondon't useto_date`.
select *
from tbldeptdivision
where deptid=21
and trunc(sysdate) between trunc(fromdate)
and trunc(todate)

As your todate is a date your problem stems from the useless conversion of the column's value from a date to a varchar and back to a date:
to_date() converts a VARCHAR to a DATE value. If the value you pass to that function is already a DATE Oracle will first implicitely convert your date to a varchar by applying the default NLS format and will then convert that varchar back to a date, again applying the default NLS format.
In the first (implicit) conversion you are losing the century in your year, which consequently is then wrong when the varchar is converted back to a date
So in your case the following is done due to the call to_date(fromdate,'dd-Mon-yyyy')
todate contains the (real) date value: 1980-01-30
the implicit conversion to a varchar makes that '01-JAN-80'
the conversion from the varchar to a date then assumes the year 80 should be 2080 (again based on the rules for implicit data type conversion).
The general rule is:
Do NOT use to_date() on a DATE (or TIMESTAMP) column
If you need to get rid of the time part in the DATE column use trunc() instead:
where trunc(sysdate) between trunc(fromdate) and trunc(todate)

Using functions on fields in your where clause slows down production. This is the same logic and will run faster.
where fromdate <= trunc(sysdate)
and todate > trunc(sysdate )

Related

How to fetch month from date where date column is in varchar datatype. FYI using snowflake tool

How to fetch month from date where date column is in varchar datatype. FYI using snowflake tool.
For example if i want data of june month ? how can i fetch ?
You can use the TO_DATE(…) function to treat the VARCHAR column as a formatted date type, and the EXTRACT(…) function to retrieve just the month out of the date.
If your date string is formatted in a well-known manner, TO_DATE's automatic parsing (or a direct cast using the :: operator) will suffice, and you can write your query this way:
SELECT * FROM table
WHERE
EXTRACT(month, TO_DATE(varcharCol)) = 6 -- June of every year
AND EXTRACT(year, varcharCol::DATE) = 2020; -- June of 2020 alone
Alternatively, if the date is in a non-standard format, use available formatting options to make TO_DATE(…) parse it properly:
-- Dates of custom format, such as: 'June # 02 # 2020'
SELECT
EXTRACT(month, TO_DATE(varcharCol, 'MMMM # DD # YYYY')) AS month
FROM table
WHERE
month = 6;
Note: You can also swap all DATE and TO_DATE above with TIMESTAMP and TO_TIMESTAMP if the data carries a whole timestamp value within it instead of only a date.
First of all, you shouldn't store dates as strings. But you probably know that.
If you do store dates as strings, you store them all in one particular format, say, 'mm/dd/yyyy'. So, use a substring function to get the month digits.
For 'mm/dd/yyyy':
where substring(date_string, 1, 2) = '06'
For 'yyyy-mm-dd':
where substring(date_string, 9, 2) = '06'
In many situations you can also use LIKE:
For 'mm/dd/yyyy':
where date_string like '06%'
For 'yyyy-mm-dd':
where date_string like '%-06-%'
You have to use to_date in snowflake to convert varchar datatype to date as following
select *
from yourTable
where to_date(yourDateColumn, 'YYYY-MM-DD') >= '2020-06-01'
and to_date(yourDateColumn, 'YYYY-MM-DD') <= '2020-06-30'

ORA-01847 - SELECT returns no result

I have a table TIGER in a schema OFO.
I have a column AS_OF_DATE with a data type DATE.
I have values in this column as follows:
2017-01-31 00:00:00
2017-02-28 00:00:00
2017-03-31 00:00:00
But I also have 1 unwanted value (that I want to delete, but I want to SELECT it via sql statement first):
0030-09-20 17:00:00
I use TOAD to see these values in Schema Browser.
I can also use a select to return me the values, this one works, it returns me results:
SELECT AS_OF_DATE from OFO.TIGER where AS_OF_DATE='2017-01-31'
But the following select does not work:
SELECT AS_OF_DATE from OFO.TIGER where AS_OF_DATE='0030-09-20'
It gives me an error:
ORA-01847: day of month must be between 1 and last day of month tips
The date is obviously in wrong format, but somehow someone managed to add that value, now I want to delete it (all the rows that have AS_OF_DATE='0030-09-20').
Your queries are relying on the evil implicit data type conversion. '2017-01-31' is a string constant not a DATE constant. The rules for this conversion are defined by the NLS settings of the client.
You have two ways of specifying a proper DATE constant in Oracle:
Use an ANSI SQL date literal
SELECT *
FROM ofo.tiger
WHERE as_of_date = DATE '2017-01-31';
or
SELECT *
FROM ofo.tiger
WHERE as_of_date = DATE '0030-09-20';
An ANSI DATE literal always specifies the DATE in the ISO format yyyy-mm-dd thus there are no implicit conversion rules regarding 1930 vs. 2030
Use Oracle's to_date() function:
SELECT *
FROM ofo.tiger
WHERE as_of_date = to_date('0030-09-20', 'YYYY-MM-DD');
By specifying the format mask the year is also un-ambigous and no implicit conversion will take place.
I would write the query as follows, TRUNC statement will rip date only from the datetime column and it would suit your need correctly :
SELECT *
from ofo.tiger
where TRUNC(as_of_date) = TRUNC(to_date('0030-09-20', 'YYYY-MM-DD'));
Instead of selecting for what it is, select what it isn't:
select AS_OF_DATE
from OFO.TIGER
where not AS_OF_DATE between '1970-01-01' and '2017-12-31'

uisng to_date function still get date format picture ends before converting entire input string error

I have the following code where I want to see if a date is less than a year ago:
select id
from mytable
where id= :p_id
and (to_date(trunc(sysdate), 'yyyy-mm-dd') - to_date(datewhen, 'yyyy-mm-dd')) < 365;
I keep getting the error:
ORA-01830: date format picture ends before converting entire input
string
Looking at other question with the same error on StackOverflow I see the solution usually is to use the to_date function which I am doing so I am unsure why this is occuring. The datewhen field is of type Date.
Do not use to_date() with the columnes of DATE data type. to_date() converts character string to a value of DATE data type. It makes no sense to convert the DATE to DATE. In a first step datewhen column of type DATE will be implicitly converted into a character data type by using the default date format (that's most probably not 'yyyy-mm-dd') and this is the culprit of the ORA-01830 error.
So your statement should look something like this:
select id from mytable where id = :p_id and (trunc(sysdate) - trunc(datewhen)) < 365;
I'd calculate the difference in the months or years instead of days:
... where months_between(sysdate, datewhen) < 12
If your datewhen column is char/varchar formatted as yyyy-mm-dd then you have to do the to_date conversion on datewhen, but not on SYSDATE: it's already a date and doesn't need to be converted.
To filter on a date within the past 365 days, compare it to SYSDATE - 365:
select id
from mytable
where id = :p_id
and to_date(datewhen, 'yyyy-mm-dd') > sysdate - 365;
But a year isn't always 365 days: on leap years it's 366 days. To get a one year ago value that's always correct, subtract an interval of one year from the current date:
select id
from mytable
where id = :p_id
and datewhen > sysdate - interval '1' year;
One more thing: the Oracle DATE type isn't just a date; it's a date and a time. SYSDATE returns the current date and time. Try this query:
select to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss') from dual;
Unless you run this at exactly midnight you'll see a time component as well.
Say your query runs on 2 September 2017 at 10 AM and you're looking for a date within the past year. You'd expect to get the date 3 September 2016, but you wouldn't because at 10 AM SYSDATE is 3 September 2016 at 10:00:00. That's greater than the plain date 3 September 2016, which is 3 September 2016 at 0:00:00, so records with a datewhen of `2016-09-03' won't be included.
To ignore the time component of an Oracle DATE value, use TRUNC. Your final query should look something like this:
select id
from mytable
where id = :p_id
and datewhen > trunc(sysdate) - interval '1' year;
you use TO_DATE function when the value in character format
Syntax
The syntax for the TO_DATE function in Oracle/PLSQL is:
TO_DATE( string1 [, format_mask] [, nls_language] )

Difference of date with SYSDATE - Value give something?

When subtracting today's date like below gives correct output.
select
(TRUNC(to_date('25/05/2016','dd/mm/yyyy'))-TRUNC(to_date('02/01/2016','dd/mm/yyyy')))
from dual;
output : 144 days
When taking todays date ad sysdate below should give 144. but shows some other value? Why?
select
(to_date(SYSDATE,'dd/mm/yyyy'))-(to_date('02/01/2016','dd/mm/yyyy'))
from dual;
output: -730343 (shows some value).
When you do:
to_date(SYSDATE,'dd/mm/yyyy')
you're implicitly converting SYSDATE, which is already a date, to a string - using your NLS_DATE_FORMAT. From the result that seems to be DD-MON-RR. So you're really doing:
to_date(to_char(SYSDATE,'DD-MON-RR'),'dd/mm/yyyy')
The inner part gives you the string '25-MAY-16'. When you convert that back to a date with the yyyy mask you have a two-digit year, 16, which is interpreted as year 0016 rather than 2016. You'd actually get what you expect if you used rrrr instead, but that's a happy side effect, and it'll still break in session with different NLS settings:
select to_date(SYSDATE,'dd/mm/yyyy') as bad_nls,
to_char(to_date(SYSDATE,'dd/mm/yyyy'), 'YYYY-MM-DD') as bad_string,
to_date(SYSDATE,'dd/mm/rrrr') as ok_nls,
to_char(to_date(SYSDATE,'dd/mm/rrrr'), 'YYYY-MM-DD') as ok_string
from dual;
BAD_NLS BAD_STRING OK_NLS OK_STRING
--------- ---------- --------- ----------
25-MAY-16 0016-05-25 25-MAY-16 2016-05-25
Notice that with your current NLS mask and the implicit conversion to a string you can't tell the difference between the first and third result; but it's obvious that it's wrong when shown with a four-digit year in the second and fourth results.
With your implicit conversion you're comparing 0016-05-25 with 2016-01-02, and it is giving you -730343 as that's how many days there are in 2000 years, adjusted for the 144 days you expected the gap to be.
As Praveen already said you don't need to use to_date() for SYSDATE, and if you're trying to set the time portion to midnight you can just truncate it.
select date '2016-05-25' - date '2016-01-02' as diff1,
date '2016-05-25' - date '0016-05-25' as diff2,
date '0016-05-25' - date '2016-01-02' as diff3,
trunc(sysdate) - date '2016-01-02' as diff4
from dual;
DIFF1 DIFF2 DIFF3 DIFF4
---------- ---------- ---------- ----------
144 730487 -730343 144
More generally, though, don't use two-digit years (alas it seems we've already forgotten the lessons of Y2K!), and don't rely on NLS settings.
You don't need to convert a date [sysdate] to date using to_date
Use trunc to strip the time portion of the sysdate.
Try;
select
TRUNC(SYSDATE) - (to_date('02/01/2016','dd/mm/yyyy'))
from dual;

SQL How to parse text value(VARCHAR) and then get milliseconds value?

There are varchar column may contain this examples (only 3 variants of values):
Oct 15, 2013 |
15/10/2013 |
2013-10-15
Need to update column values and set the appropriate values for milliseconds: 1381723200000. Without changing type column.
Oracle Perspective:
If you want to extract Milliseconds from a string with YYYY-DD-MM format or whatever (without milliseconds)
SELECT
TO_CHAR( TO_TIMESTAMP ( '2013-10-15',
'YYYY-MM-DD' ),'FF9')
FROM
DUAL;
will give you 000000000 always in Oracle, since there is no milliseconds value stored in your string.
But, if you want to convert the date into milliseconds, then
Milliseconds since when???
SELECT
( TO_DATE ( '2013-10-16',
'YYYY-MM-DD' ) -- starting date
- TO_DATE ( '2013-10-15',
'YYYY-MM-DD' )) -- ending date
*24*60*60*1000 -- milliseconds multiplication factor
FROM
DUAL;