(Oracle)Getting 30 days before - sql

My goal is to get 30 days before.
The data are stored as varchar2 type, '20200630' and '20200613'.
The expected result is '20200531' and '20200514' for each.
I have simply subtracted 30 from my varchar2 '20200630' and '20200613' and
it shows result by casting, but the result are not expected such as '20200600','20200583' which are not form of date.
Could I know how to modify my code as below
WITH A AS
(SELECT '20200630' YEARMONTHDAY FROM DUAL
UNION ALL
SELECT '20200613' FROM DUAL)
SELECT YEARMONTHDAY - 30 FROM A;

Store your data using the appropriate type! That is, use date rather than a string.
If you are stuck with data in this format, convert to date:
select to_date(yearmonthday, 'YYYYMMDD') - interval '30' day
I would not recommend converting the value back to a string. Dates should be dates.

Related

Create a datetime value from separate date time columns

I have individual columns for year, month, day, hour, minute, second and millisecond. I need to combine them all together into a date timestamp. I am able to make a date value, but can't seem to make a valid time one. I am working in Oracle and I have sample below. I'd like my value to look like the createtime column.
This did the trick:
to_timestamp(XT.MONTH1||'-'||XT.DAY1||'-'||XT.YEAR||' '|| xt.hour24||'.'||xt.minute||'.'||xt.second||'.'||xt.milliseconds,'MM-DD-YYYY HH24:MI:SS.FF')
That is quite easy but not pretty. You convert the columns from datatype NUMBER to VARCHAR2 padded with leading zeros, using fm to suppress any spaces for + or -:
SELECT TO_CHAR(month,'fm00') FROM mytable;
05
Next, you glue the converted columns together with the || operator to get a single, long, string:
SELECT TO_CHAR(year,'fm0000')||TO_CHAR(month,'fm00')|| ...
20200519...
This long string can now be converted to datatype DATE, or, in your case TIMESTAMP as you have milliseconds. You need to specify the date format you used, f.i. 'YYYYMMDD...'
SELECT TO_TIMESTAMP(TO_CHAR(year,'fm0000')|| ... , 'YYYYMM')
A complete example looks like:
SELECT TO_TIMESTAMP(
TO_CHAR(year,'fm0000')||TO_CHAR(month,'fm00')||
TO_CHAR(day,'fm00')||TO_CHAR(hour24,'fm00')||
TO_CHAR(minute,'fm00')||TO_CHAR(second,'fm00')||
TO_CHAR(ms,'fm000')
, 'YYYYMMDDHH24MISSFF3')
FROM (-- your table, as a mockup, I'll use DUAL
SELECT 2020 as year, 5 as month, 19 as day,
13 as hour24, 7 as minute, 10 as second,
300 as ms
FROM DUAL);
2020-05-19 13:07:10,300000000
EDIT:
The fill mode modifier fm supresses a leading space for positive numbers (to make room for the - sign for negative numbers). All parts of a date are positive, so you get a lot of spaces in your string.
SELECT TO_CHAR(x,'99'), TO_CHAR(x,'fm99')
FROM (SELECT -10 as x FROM DUAL UNION ALL SELECT 10 FROM DUAL);
| 10|10|
|-10|-10|
The documentation is a bit hidden under Format Model Modifiers.
Come to think of it, you might as well keep the spaces and adjust your format model:
SELECT TO_TIMESTAMP(
TO_CHAR(year,'0000')||TO_CHAR(month,'00')||
TO_CHAR(day,'00')||TO_CHAR(hour24,'00')||
TO_CHAR(minute,'00')||TO_CHAR(second,'00')||
TO_CHAR(ms,'000')
,' YYYY MM DD HH24 MI SS FF3')
FROm (SELECT 2020 as year, 5 as month, 19 as day,
13 as hour24, 7 as minute, 10 as second,
300 as ms FROM DUAL);

Can not convert varchar to Date

I have a table with dates as a varchar type and the resulted date output (Begin_date) is in the '20130630' format.
I need to convert the begin date output as a date. It doesn't matter what date format as long as it is a date.
I have tried these but none seems to work. I get the ORA-01843 not a valid month error.
to_date(aa.Begin_date, 'yyyymmdd')
to_char(to_date(aa.Begin_date, 'yyyymmdd'), 'dd-mm-yy')
to_char(to_date(aa.Begin_date, 'yyyymmdd'), 'dd-MON-yy')
2) Additionally , some begin dates have this format 20030000. Essentially meaning we only know the year. I need to have a output that input a January 1 and year (doesn't matter format).
Case when aa.begin_date between '1900' and '2030'
then to_date('0101'+aa.begin_date,'YYYYMMDD')
I tried a like statement
case when aa.begin_date like '%0000'
then to_date('0101'+aa.begin_date,'YYYYMMDD')
end as tes
You can try something like this:
with test_data as
( select '20130630' begin_date from dual
union
select '20030000' begin_date from dual
)
select
case when test_data.begin_date like '%0000' then
to_date(substr(begin_date,1,4)||'0101','YYYYMMDD')
else to_date(begin_date,'YYYYMMDD') end my_date
from test_data
But best thing is to correct your data model to use real DATE type. Storing dates as a string is a bad design.
this will work:
SELECT to_date('20130630','YYYYMMDD') FROM dual

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] )

In Oracle, how do I subtract a month from timestamp retaining the millisecond part [duplicate]

This question already has answers here:
Add 2 months to current timestamp
(5 answers)
Closed 8 years ago.
In Oracle, how do I subtract a month from timestamp retaining the millisecond part.
I am using add_months function but it is truncating the milliseconds. Is there a built in function or I have to manually extract month part of timestamp and add to it?
When you use add_months() function, data type conversion takes place - the value of timestamp data type becomes a value of date data type, which does not have fractional seconds.
As #jonearles absolutely correctly pointed out in a comment to the answer, using presented above method to subtract one or more months from a given value of timestamp data type preserving milliseconds, may cause ORA-01839: date not valid for month specified.
To prevent that error from popping up, the query can be rewritten as follows:
clear screen;
with t1(col) aS(
select current_timestamp from dual union all
select timestamp '2000-03-30 12:12:12.123' from dual union all
select timestamp '2014-03-30 01:12:59.64567' from dual
)
select col as cur
, cast(add_months(col, -1) as timestamp) + (col - cast(col as date)) as prev
from t1
Result:
CUR PREV
-------------------------------------- -------------------------------
14-FEB-14 01.45.46.344187000 PM 14-JAN-14 01.45.46.344187000 PM
30-MAR-00 12.12.12.123000000 PM 29-FEB-00 12.12.12.123000000 PM
30-MAR-14 01.12.59.645670000 AM 28-FEB-14 01.12.59.645670000 AM
You can get it done by using year to month interval literal (can produce invalid dates):
clear screen;
select current_timestamp as res_1
, current_timestamp - interval '1' month as res_2
from dual
Result:
RES_1 RES_2
------------------------------ -----------------------------
05-FEB-14 02.02.32.383089000 05-JAN-14 02.02.32.383089000

Retrieve previous month from date column that contains MONYYYY

I need to change a date value that is coming from a table in the form of May2013 (MonYYYY). The column itself is a VARCHAR
In my select statement, I am looking to retrieve the previous month (Apr2013). I've done some research and found the following, if I were using SYSDATE:
select to_date(add_months(sysdate, 'MONYYY')-1) from dual
How do I make it work for the date structure I have above? I've tried:
select to_date(add_months(date.datetable, MONYYY)-1) from datetable
ADD_MONTHS function needs a date variable as input. So, first you need to convert your varchar column to date type and then apply the add_months function.
SELECT ADD_MONTHS (TO_DATE ('May2013', 'monyyyy'), -1) FROM DUAL;
The return type will be date. In this case, it returns 0th hour of first day of April.