fetch records between 'current date ' and next 5 days(future date) in oracle - sql

Select * from dual where between to_date(date,'YYYY-MM-DD') = '2020-10-01'
and to_date(date,'YYYY-MM-DD') + 5
this is correct way to write query?
1.format of date is varchar2
2.required data between current date and next 5 days
3.first needs to convert into date format.
4. next 5 should be +5 in current day

You probably meant to write:
where to_date(mydate, 'yyyy-mm-dd') between trunc(sysdate)
and trunc(sysdate) + 5
Rationale:
date is a reserved word; I assume that's not the actual name of your column, so I used something else; if that's the real name, then you need to surround it with double quotes ("date", or "DATE", or else, depending on how it was initially defined)
mydate is a string so you need to turn it to a date: for this, you can use to_date()
you then compare it to the current date, without the time portion : trunc(sysdate), and the same date 5 days later
Note, however, that this would be more efficiently expressed as follows:
where mydate between to_char(trunc(sysdate), 'yyyy-mm-dd')
and to_char(trunc(sysdate + 5), 'yyyy-mm-dd')
This avoids the date conversion on the string column, and instead converts the interval bounds. Here, string comparison is possible, because the format of the string you are storing allows it (it it was stored as dd-mm-yyyy' for example, this would not be possible).
Let me, however, strongly suggest to store your dates as dates rather than string. You should always use the proper datatype, for many reason, such as data integrity and efficency.

Related

How to extract month number from date in Oracle

I have ID_BB_SECURITY column where the date value is stored in this column for example '20190801'.
I want to get month number from this field for example for August date i want to get 8.
I tried below query but it throws an error 'literal does not match':
select to_number(to_date(ID_BB_SECURITY),'mm') from BT_EXPORT
I am not sure if i have to ignore null values so as to avoid the error
If the value is a number or string then you can convert it to a date with an appropriate mask - which is what you are missing, and what is causing the error you are getting (as it's using your session's NLS_DATE_FORMAT setting, which apparently does not match the format of the data; but which you should not rely on anyway, as #MTO said in comments):
to_date(ID_BB_SECURITY, 'YYYYMMDD')
and then extract the month number from that:
select extract(month from to_date(ID_BB_SECURITY, 'YYYYMMDD')) from BT_EXPORT
Or you could just use a substring:
select to_number(substr(ID_BB_SECURITY, 5, 2)) from BT_EXPORT;
Those assume a fixed consistent format, which is always a risky assumption when using the wrong data type. Ans if it's a number they are doing an implicit conversion from number to string, which you could turn into an explicit conversion for greater clarity.
If it's already a date - as it should be, of course - then you don't need the conversion:
select extract(month from ID_BB_SECURITY) from BT_EXPORT
If you have a number, you can use arithmetic to extract the month:
select mod(floor(20190801 / 100), 100)
from dual;
You could try converting the number date to a string, and then extracting the 5th and 6th characters:
SELECT
SUBSTR(TO_CHAR(ID_BB_SECURITY), 5, 2) AS mm
FROM BT_EXPORT;
But, it would be much better for you to use a proper date column. Then, you could use a less draconian method such as:
SELECT
TO_CHAR(ID_BB_SECURITY, 'mm') AS mm -- assuming date
FROM BT_EXPORT;
select to_number(to_char(to_date('20190801', 'yyyymmdd'), 'mm')) from dual
Try this one
select extract(month from to_date(ID_BB_SECURITY, 'YYYYMMDD')) from BT_EXPORT
This one convert number to date then extract month.
also
select extract(month from to_date('20190801', 'yyyymmdd')) from dual
Your date column has the value stored in the following format "yyyymmdd" where
yyyy is the year
mm the month
dd the day
So in order to return the number value of the month (mm) we can do as follows:
1: first transform the value from a number to a date using
to_date(20190801,'yyyymmdd')
2: get month using to_date operator
to_char( to_date(20190801,'yyyymmdd'), 'mm')

How to compare 2 converted dates in sql

I'm trying to exclude results in my query that start in the same month between two columns. For example, I need to exclude benefits1 that start in the same month as benefits2. Format for benefit1_start_date and benefit2_start_date is: YYYYMMDD.
This is what I have so far:
where (benefit1_start_date = (to_char(sysdate, 'YYYYMM') || '0122')) <>
(benefit2_start_date = (to_char(sysdate, 'YYYYMM') || '0122'));
If anyone could put me in the right direction, I'd greatly appreciate it!
Convert your numeric dates to text, and then compare the year and month substrings:
WHERE
SUBSTR(TO_CHAR(benefits1_start_date), 1, 6) <> SUBSTR(TO_CHAR(benefits2_start_date), 1, 6)
Note that storing your dates as numbers like this is atypical, and you might want to consider storing them as dates. If you don't have a day component, you could just use the first as a placeholder.
As I understand it, you want to eliminate records where your 2 columns benefits1_start_date and benefits2_start_date are in the same month, and both have a format of YYYYMMDD.
Are they stored as strings? If so, all you need to do is compare the first 6 characters (if you need to consider yr + month), or just the 5+6th characters if you want to check just the month without the year.
Year + Month:
SUBSTR(benefits1_start_date,1,6) <> SUBSTR(benefits2_start_date,1,6)
Just month:
SUBSTR(benefits1_start_date,5,2) <> SUBSTR(benefits2_start_date,5,2)
If they're not stored as strings but as dates, then you can TRUNC the date to month and compare (for yr + month), or convert the date to MM string via to_char and compare if you just want to check the month.
Hope this helps.
I suggest you to use BETWEEN clause. Converting LEFT side operand to string by function and then making comparison can have severe performance impacts.
if you convert indexed table.dateColumn to string by to_char(table.dateColumn), oracle cannot use defined index on column anymore.
Your desired query:
where to_char(benefit1_start_date, 'YYYYMM') != to_char(benefit2_start_date, 'YYYYMM')
but
select * from table1
where months_between(benefit1_start_date, benefit2_start_date) not between -1 and 1
would be what you are looking for. (no performance impact)

SQL convert into Data field to compare with current date

I have one field in a Firebird DB containing dates like this
27.09.2014
untill no I compared it to the current date with
substring(100+extract(day from current_date) from 2 for 2)
|| '.' ||
substring(100+extract(month from current_date) from 2 for 2)
|| '.' ||
extract(year from current_date)
= date_field_to_compare
But now i need to keep out the greater dates and this turns out to be impossible in this case, since its not handling native dates but numbers.
So I actually need to do the opposite, to convert the
27.09.2014
into A SQL date.
Like
SELECT date_field_to_compare FROM db WHERE
date_field_to_compare < CURRENT_DATE
But how can I Convert this DB Date field into a SQL understandable date?
You shouldn't store dates in (VAR)CHAR fields, store them in a DATE. It will solve these types of problems, and make things like selecting, sorting etc a lot easier.
That said Firebird supports a number of date conversions from string, and dd.MM.yyyy is one of them:
SELECT CAST('27.09.2014' AS DATE) FROM RDB$DATABASE
Or:
SELECT date_field_to_compare
FROM db
WHERE CAST(date_field_to_compare AS DATE) < CURRENT_DATE
Related: https://stackoverflow.com/a/23857635/466862

Select Varchar as Date

I want to select a varchar field as a date field
For example a field has this value "30.12.2011 21:15:03"
and when i select this
select DATE from TABLE where DATE = '30.12.2011'
i get no result.
You ask about getting the date part of a timestamp field, but what your question is actually about is filtering on the date of a timestamp field. There is a much simpler method of accomplishing that: you can use the knowledge that all the possible timestamps on a specific date won't have any timestamps for different dates between them.
select DATE
from TABLE
where DATE >= '30.12.2011' and DATE < '31.12.2011'
Your edit explains that you haven't got a timestamp field at all. Nevertheless, a similar approach may still work:
select DATE
from TABLE
where DATE LIKE '30.12.2011 %'
Or the Firebird-specific
select DATE
from TABLE
where DATE starting with '30.12.2011 '
Assuming the field is a date field, use the DATE introducer combined with yyyy-mm-dd (or TIMESTAMP with time as well).
So use:
select datefield from sometable where datefield = DATE '2011-12-30'
Technically you can leave off the introducer, but it is 'correcter' in the light of the SQL standard.
Assuming a TIMESTAMP field, you won't get results unless the timestamp is (always) at 00:00:00.0000 (in which case it should have been a DATE instead).
For the comparison to work, you need to use either BETWEEN, eg:
select timestampfield from sometable
where timestampfield BETWEEN '2011-12-30 00:00:00.0000' AND '2011-12-30 23:59:59.9999'
or truncate the timestamp to a date (this may adversely effect performance if the timestamp is indexed, because then the index can no longer be used), eg:
select timestampfield from sometable
where CAST(timestampfield AS DATE) = '2011-12-30'
If the date is stored in a VARCHAR field (which in itself is a bad idea), there are several solutions, first is to handle it as date manipulation:
select varcharfield from sometable
where CAST(CAST(varcharfield AS TIMESTAMP) AS DATE) = '2011-12-30'
The double cast is required if you have a time-component in VARCHARFIELD as well. This assumes dates in the supported format listed below. If you use BETWEEN as above, you can use a single cast to timestamp)
The other solution (as suggested by hvd) is to treat it purely as string manipulation, for example:
select varcharfield from sometable
where varcharfield STARTING WITH '30.12.2011'
This has its own set of problems if you want to select ranges. Bottomline: use a real TIMESTAMP field!
Note that Firebird supports multiple formats:
yyyy-mm-dd, eg 2014-05-25 (ISO-8601 format, probably best to use as it reduces confusion)
dd.mm.yyyy, eg 25.05.2014
mm/dd/yyyy, eg 05/25/2014
mm-dd-yyyy, eg 05-25-2014
dd mmm yyyy, eg 25 MAY 2014 (+ variations with a -, . or / as separator)
mmm dd yyyy, eg MAY 25 2014 (+ variations with a -, . or / as separator)
select DATE from TABLE where cast(DATE as date) = '30.12.2011'
Date field is a timestamp
Here is the answere to my question:
CAST
(
SUBSTRING
(field FROM 1 FOR 2)
||'.'||
SUBSTRING
(field FROM 4 FOR 2)
||'.'||
SUBSTRING
(field FFROM 7 FOR 4)
AS DATE)
This took me 5 hours to find this out, maybe there should be a "-" instead of "." but it works.

In Oracle, convert number(5,10) to date

When ececute the following SQL syntax in Oracle, always not success, please help.
40284.3878935185 represents '2010-04-16 09:18:34', with microsecond.
an epoch date of 01 January 1900 (like Excel).
create table temp1 (date1 number2(5,10));
insert into temp1(date1) values('40284.3878935185');
select to_date(date1, 'yyyy-mm-dd hh24:mi:ssxff') from temp1
Error report: SQL Error: ORA-01861: literal does not match format
string
01861. 00000 - "literal does not match format string"
*Cause: Literals in the input must be the same length as literals in
the format string (with the exception of leading whitespace). If the
"FX" modifier has been toggled on, the literal must match exactly,
with no extra whitespace.
*Action: Correct the format string to match the literal.
Thanks to Mark Bannister
Now the SQL syntax is:
select to_char(to_date('1899-12-30','yyyy-mm-dd') +
date1,'yyyy-mm-dd hh24:mi:ss') from temp1
but can't fetch the date format like 'yyyy-mm-dd hh24:mi:ss.ff'. Continue look for help.
Using an epoch date of 30 December 1899, try:
select to_date('1899-12-30','yyyy-mm-dd') + date1
Simple date addition doesn't work with timestamps, at least if you need to preserve the fractional seconds. When you do to_timestamp('1899-12-30','yyyy-mm-dd')+ date1 (in a comment on Mark's answer) the TIMESTAMP is implicitly converted to a DATE before the addition, to the overall answer is a DATE, and so doesn't have any fractional seconds; then you use to_char(..., '... .FF') it complains with ORA-01821.
You need to convert the number of days held by your date1 column into an interval. Fortunately Oracle provides a function to do exactly that, NUMTODSINTERVAL:
select to_timestamp('1899-12-30','YYYY-MM-DD')
+ numtodsinterval(date1, 'DAY') from temp3;
16-APR-10 09.18.33.999998400
You can then display that in your desired format, e.g. (using a CTE to provide your date1 value):
with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')
+ numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SSXFF') from temp3;
2010-04-16 09:18:33.999998400
Or to restrict to thousandths of a second:
with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')+
+ numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SS.FF3') from temp3;
2010-04-16 09:18:33.999
An epoch of 1899-12-30 sounds odd though, and doesn't correspond to Excel as you stated. It seems more likely that your expected result is wrong and it should be 2010-04-18, so I'd check your assumptions. Andrew also makes some good points, and you should be storing your value in the table in a TIMESTAMP column. If you receive data like this though, you still need something along these lines to convert it for storage at some point.
Don't know the epoch date exactly, but try something like:
select to_date('19700101','YYYYMMDD')+ :secs_since_epoch/86400 from dual;
Or, cast to timestamp like:
select cast(to_date('19700101', 'YYYYMMDD') + :secs_since_epoch/86400 as timestamp with local time zone) from dual;
I hope this doesn't come across too harshly, but you've got to totally rethink your approach here.
You're not keeping data types straight at all. Each line of your example misuses a data type.
TEMP1.DATE1 is not a date or a varchar2, but a NUMBER
you insert not the number 40284.3878935185, but the STRING >> '40284.3878935185' <<
your SELECT TO_DATE(...) uses the NUMBER Temp1.Date1 value, but treats it as a VARCHAR2 using the format block
I'm about 95% certain that you think Oracle transfers this data using simple block data copies. "Since each Oracle date is stored as a number anyway, why not just insert that number into the table?" Well, because when you're defining a column as a NUMBER you're telling Oracle "this is not a date." Oracle therefore does not manage it as a date.
Each of these type conversions is calculated by Oracle based on your current session variables. If you were in France, where the '.' is a thousands separator rather than a radix, the INSERT would completely fail.
All of these conversions with strings are modified by the locale in which Oracle thinks your running. Check dictionary view V$NLS_PARAMETERS.
This gets worse with date/time values. Date/time values can go all over the map - mostly because of time zone. What time zone is your database server in? What time zone does it think you're running from? And if that doesn't spin your head quite enough, check out what happens if you change Oracle's default calendar from Gregorian to Thai Buddha.
I strongly suggest you get rid of the numbers ENTIRELY.
To create date or date time values, use strings with completely invariant and unambiguous formats. Then assign, compare and calculate date values exclusively, e.g.:
GOODFMT constant VARCHAR2 = 'YYYY-MM-DD HH24:MI:SS.FFF ZZZ'
Good_Time DATE = TO_DATE ('2012-02-17 08:07:55.000 EST', GOODFMT);