convert into date format oracle there is an identical question in the continuation of this discussion.
I have a field c_day in the table my_table that accepts numeric values from 1 to 31. In this field. I need to add 210 days to today's date, and insert the value from c_day from the released date dd.mm.yyyy. For example, we take today's date 08.02.2023 and add 210 days to it, the date falls on September, and if c_day is 20, then the output should be 20.09.2023. But if c_dayis equal to 31, then of course the date should be set as 30.09.2023, because the last day of September is 30.
Now I settled on cases where September ends on the 30th, and the field takes values from 1 to 31. How can I write a condition in such cases so that it takes the last day of the month?
I tried this one, but it doesn't work:
SELECT
C_DAY,
LEAST(
TO_DATE(TO_CHAR(TRUNC(SYSDATE) + 210, 'YYYY-MM-') || C_DAY, 'YYYY-MM-DD'),
CASE
WHEN C_DAY < TO_CHAR(LAST_DAY(TRUNC(SYSDATE) + 210), 'DD') THEN
last_day(TO_DATE(TO_CHAR(TRUNC(SYSDATE) + 210, 'YYYY-MM-') || C_DAY, 'YYYY-MM-DD'))
END
) as result
FROM MY_TABLE
ORDER BY 1
You can can do it without any string manipulation using:
SELECT C_DAY,
LEAST(
TRUNC(TRUNC(SYSDATE) + 210, 'MM') + C_DAY - 1,
LAST_DAY(TRUNC(SYSDATE) + 210)
) AS result
FROM MY_TABLE
ORDER BY c_day
Which, for the sample data:
CREATE TABLE my_table ( c_day ) AS
SELECT LEVEL FROM DUAL CONNECT BY LEVEL <= 31;
Outputs:
C_DAY
RESULT
1
2023-09-01 00:00:00
2
2023-09-02 00:00:00
3
2023-09-03 00:00:00
...
...
28
2023-09-28 00:00:00
29
2023-09-29 00:00:00
30
2023-09-30 00:00:00
31
2023-09-30 00:00:00
fiddle
Related
If i give input year like '2021' i need result as below
Month Start Date End Date
1 1/1/2021 31/01/2021
2 1/2/2021 28/01/2021
.
.
.
.
.
.
.
.
.
12 1/12/2021 31/12/2021
Basically, it is about the row generator technique; there are plenty of them, pick any you want. (Have a look at OraFAQ).
For example:
SQL> with mon as
2 (select add_months(trunc(to_date(&par_year, 'yyyy'), 'yyyy'), level - 1) val
3 from dual
4 connect by level <= 12
5 )
6 select to_char(val, 'mm') mon,
7 val start_date,
8 last_day(val) end_date
9 from mon
10 order by 1;
Enter value for par_year: 2021
MO START_DATE END_DATE
-- ---------- ----------
01 01/01/2021 31/01/2021
02 01/02/2021 28/02/2021
03 01/03/2021 31/03/2021
04 01/04/2021 30/04/2021
05 01/05/2021 31/05/2021
06 01/06/2021 30/06/2021
07 01/07/2021 31/07/2021
08 01/08/2021 31/08/2021
09 01/09/2021 30/09/2021
10 01/10/2021 31/10/2021
11 01/11/2021 30/11/2021
12 01/12/2021 31/12/2021
12 rows selected.
SQL>
You could also use directly the model clause for that purpose.
SELECT n
, TO_DATE(&the_year||lpad(f, 2, '0'), 'YYYYMM') start_dt
, last_day(TO_DATE(&the_year||lpad(f, 2, '0'), 'YYYYMM')) end_dt
FROM DUAL
MODEL
DIMENSION by (1 as n)
MEASURES (1 as f)
RULES (
f[FOR n FROM 1 TO 12 INCREMENT 1 ] = cv(n)
)
;
The advantage of the model clause is if you later want to get the every other month, you just need to change the increment from 1 to 2. Or if you are looking for the quarter months of the year (January, April, Jully, October), you just need to change increment from 1 to 3, and so on...
Just replace 2021 in the query for your year
with months (m) as (
select 1 from dual union all
select m + 1 from months where m < 12
)
select
to_date('2021' || '-' || to_char(m) || '-01', 'YYYY-MM-DD') as first_day,
last_day(to_date('2021' || '-' || to_char(m) || '-01', 'YYYY-MM-DD')) as last_day
from months
You can try on this db<>fiddle
Try below query
WITH cte_date as(
SELECT
LEVEL Month_No,
to_date(to_char(LEVEL||'-2021'),'MM-YYYY') Start_Date FROM dual
CONNECT BY LEVEL <=12
)
SELECT Month_No, Start_Date, LAST_DAY(Start_Date) End_Date
FROM cte_date;
I'm a fan of recursive CTEs because they are part of Standard SQL. I would phrase this as:
with months (month, startdate) as (
select 1 as month, date '2021-01-01'
from dual
union all
select month + 1, add_months(startdate, 1)
from months
where month < 12
)
select month, startdate, last_day(startdate) as enddate
from months;
If you need an input year, there are different ways to accomplish it. But a simple way is to change the second line to:
select 1 as month, to_date(:year || '0101', 'YYYYMMDD')
Please does anyone have an idea on how to calculate current date (only dd/mm) by counting the number of days since the 1st January?
You can just add 157 to the first day of the year:
select trunc(sysdate, 'YYYY') + 157 from dual;
TRUNC(SYSDATE,'YYYY')+157
-------------------------
2016-06-06
The trunc(sysdate, 'YYYY') part gives you the first day of the year. You can also use a fixed date:
select date '2016-01-01' + 157 from dual;
DATE'2016-01-01'+157
--------------------
2016-06-06
And you can use an interval rather than a plain number of days if you prefer:
select date '2016-01-01' + numtodsinterval(157, 'DAY') from dual;
DATE'2016-01-01'+NUMTODSINTERVAL(157,'DAY')
-------------------------------------------
2016-06-06
Read more about datetime/interval arithmetic.
Either way of you only want DD/MM then use to_char():
select to_char(date '2016-01-01' + 157, 'DD/mM') from dual;
TO_CH
-----
06/06
I'm trying to insert weekly dates in my table, the start date is always on Fridays and the end date is always on thursday. I'm using this code :
CREATE TABLE WEEK AS
WITH generator AS (
SELECT DATE '2015-01-02' + LEVEL - 1 dt
FROM dual
CONNECT BY LEVEL <= DATE '2016-01-21' - DATE '2015-01-02' + 1
)
SELECT to_char(dt, 'YYYY "SEM"IW') "KEY",
dt "DATE_START",
least(next_day(dt - 1, to_char(DATE '2015-01-08', 'DAY')),
last_day(dt)) "DATE_END"
FROM generator
WHERE to_char(dt, 'D') = to_char(DATE '2015-01-02', 'D');
The code is working for weeks on the same month, but if I have a starting date on a month and the finish date on the next month, there's no data inserting in my table.
For example :
Date_ START | DATE_END
29-05-2015 | 31-05-2015
05-06-2015 | 11-05-2015
Instead of 31-05-2015 I should have 04-06-2015.
I think the following is what you're after:
with generator as (select date '2015-05-29' + (level - 1)*7 dt
from dual
connect by level <= (date '2016-01-21' - date '2015-05-29')/7 + 1)
select to_char(dt, 'YYYY "SEM"IW') "KEY",
dt "DATE_START",
dt + 6 "DATE_END"
from generator;
KEY DATE_START DATE_END
---------- ---------- ----------
2015 SEM22 2015-05-29 2015-06-04
2015 SEM23 2015-06-05 2015-06-11
2015 SEM24 2015-06-12 2015-06-18
2015 SEM25 2015-06-19 2015-06-25
<snip>
2016 SEM01 2016-01-08 2016-01-14
2016 SEM02 2016-01-15 2016-01-21
This is assuming that the dates you have specified in the generator subquery have already been determined to be a Friday. Otherwise you could use something like trunc(<date> - 4, 'iw') + 4 or trunc(<date> + 3, 'iw') + 4 (depending on whether you want the previous or next Friday to be included for the date specified) to make sure that the seed date is definitely a Friday.
Maybe just an alternative you can try analytical function here. But as
suggested by Boniest "just adding days" will be better approach. Have
fun
WITH generator AS
(SELECT DATE '2015-01-02' + LEVEL - 1 dt
FROM dual
CONNECT BY LEVEL <= DATE '2016-01-21' - DATE '2015-01-02' + 1
)
-- select * from generator;
SELECT TO_CHAR(dt, 'YYYY "SEM"IW') "KEY",
dt "DATE_START",
lead(dt) over (ORDER BY (dt)) -1 "End Date"
FROM generator
WHERE TO_CHAR(dt, 'D') = TO_CHAR(DATE '2015-01-02', 'D');
----------------------------------OUTPUT-----------------------------------------
**KEY DATE_START End Date**
2015 SEM18 05/01/2015 05/07/2015
2015 SEM19 05/08/2015 05/14/2015
2015 SEM20 05/15/2015 05/21/2015
2015 SEM21 05/22/2015 05/28/2015
2015 SEM22 05/29/2015 06/04/2015
----------------------------------------------------------------------------------
How can I add months to a timestamp value in Oracle? In my query, it's getting converted to date value instead:
SELECT add_months(current_timestamp,2)
FROM dual;
The actual output is:
ADD_MONTH
11-MAR-13
The expected output is:
2013-01-01 00:00:00.000000000+00:00
This will give you the date and the time as a TIMESTAMP data type:
select TO_TIMESTAMP(TO_CHAR(ADD_MONTHS(SYSDATE, 2), 'YYYYMMDD HH24:MI'),
'YYYYMMDD HH24:MI') from dual;
If you need more or less precision (E.G. rounding) than what is above, adjust the date formats (both need to be the same format). For example, this will return 2 months down to the seconds level of precision:
select TO_TIMESTAMP(TO_CHAR(ADD_MONTHS(SYSTIMESTAMP, 2),
'YYYYMMDD HH24:MI:SS'), 'YYYYMMDD HH24:MI:SS') from dual;
This is the closest I can get (as a character) to the format you need:
select TO_CHAR(
TO_TIMESTAMP(TO_CHAR(ADD_MONTHS(SYSTIMESTAMP, 2),
'YYYYMMDD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS'),
'YYYY-MM-DD HH24:MI:SS.FF TZR') from dual;
I think this will about give you what you're looking for:
SELECT TO_CHAR(TO_TIMESTAMP(ADD_MONTHS(CURRENT_TIMESTAMP,2))
+ (CURRENT_TIMESTAMP - TRUNC(CURRENT_TIMESTAMP)),
'YYYY-MM-DD HH:MI:SSxFFTZR') FROM DUAL;
The problem with using the interval methods is that you can get an unexpected error depending on the date you run the query. E.g.
SELECT TO_TIMESTAMP('31-JAN-2012') + NUMTOYMINTERVAL(1,'MONTH') FROM DUAL;
That query returns:
ORA-01839: date not valid for month specified
This is because it attempts to return February 31, which is not a valid date.
ADD_MONTHS is a "safer" way to date math, in that where the interval query would throw an error, ADD_MONTHS will return the last date of the month (Feb 28 or 29 depending on the year) in the above example.
For Oracle:
SELECT
TIMESTAMP'2014-01-30 08:16:32', -- TS we want to increase by 1 month
--TIMESTAMP'2014-01-30 08:16:32' + NUMTOYMINTERVAL(1, 'MONTH'), -- raises ORA-01839: date not valid for month specified
--TIMESTAMP'2014-01-30 08:16:32' + INTERVAL '1' MONTH, -- raises ORA-01839: date not valid for month specified
ADD_MONTHS(TIMESTAMP'2014-01-30 08:16:32', 1), -- works but is a date :(
CAST(ADD_MONTHS(TIMESTAMP'2014-01-30 08:16:32', 1) AS TIMESTAMP) -- works
FROM DUAL
SELECT current_timestamp + INTERVAL '2' MONTH from dual;
To display this in your desired format, use TO_CHAR:
SELECT TO_CHAR(current_timestamp + INTERVAL '2' MONTH,
'YYYY-MM-DD HH24:MI:SS.FF9TZH:TZM') from dual;
2013-03-11 23:58:14.789501000+01:00
For Oracle:
select TO_TIMESTAMP(Sysdate,'DD-Mon-YYYY HH24-MI-SS') + 60
from dual;
select sysdate + interval '2' month from dual;
select TO_TIMESTAMP (Sysdate + interval '2' month, 'DD-Mon-YYYY HH24-MI-SS')
from dual
;
Result1:
| TO_TIMESTAMP(SYSDATE,'DD-MON-YYYYHH24-MI-SS')+60 |
----------------------------------------------------
| March, 12 0013 00:00:00+0000 |
Result2:
| SYSDATE+INTERVAL'2'MONTH |
--------------------------------
| March, 11 2013 21:41:10+0000 |
Result3:
| TO_TIMESTAMP(SYSDATE+INTERVAL'2'MONTH,'DD-MON-YYYYHH24-MI-SS') |
------------------------------------------------------------------
| March, 11 0013 00:00:00+0000 |
sqlffidle demo.
I have a monthly amount that I need to spread equally over the number of days in the month. The data looks like this:
Month Value
----------- ---------------
01-Jan-2012 100000
01-Feb-2012 121002
01-Mar-2012 123123
01-Apr-2012 118239
I have to spread the Jan amount over 31 days, the Feb amount over 29 days and the March amount over 31 days.
How can I use PL/SQL to find out how many days there are in the month given in the month column?
SELECT CAST(to_char(LAST_DAY(date_column),'dd') AS INT)
FROM table1
Don't use to_char() and stuff when doing arithmetics with dates.
Strings are strings and dates are dates. Please respect the data types and use this instead:
1+trunc(last_day(date_column))-trunc(date_column,'MM')
Indeed, this is correct. It computes the difference between the value of the last day of the month and the value of the first (which is obviously always 1 and therefore we need to add this 1 again).
You must not forget to use the trunc() function if your date columns contains time, because last_day() preserves the time component.
SELECT EXTRACT(DAY FROM LAST_DAY(SYSDATE)) num_of_days FROM dual;
/
SELECT SYSDATE, TO_CHAR(LAST_DAY(SYSDATE), 'DD') num_of_days FROM dual
/
-- Days left in a month --
SELECT SYSDATE, LAST_DAY(SYSDATE) "Last", LAST_DAY(SYSDATE) - SYSDATE "Days left"
FROM DUAL
/
You can add a month and subtract the two dates
SQL> ed
Wrote file afiedt.buf
1 with x as (
2 select date '2012-01-01' dt from dual union all
3 select date '2012-02-01' from dual union all
4 select date '2012-03-01' from dual union all
5 select date '2012-01-31' from dual
6 )
7 select dt, add_months(trunc(dt,'MM'),1) - trunc(dt,'MM')
8* from x
SQL> /
DT ADD_MONTHS(TRUNC(DT,'MM'),1)-TRUNC(DT,'MM')
--------- -------------------------------------------
01-JAN-12 31
01-FEB-12 29
01-MAR-12 31
31-JAN-12 31
select add_months(my_date, 1)-my_date from dual;
SELECT TO_CHAR(LAST_DAY(SYSDATE), 'fmday-mon-rr dd') as LastDayOfMonth
FROM dual;
Use the following Oracle query:
select to_number(to_char(last_day(sysdate),'dd')) TotalDays from dual
Date_Parameter='01-Oct-2017'
select to_number(to_char(last_day('Date_Parameter'),'dd')) TotalDays from dual