sql oracle case when date - sql

This is what I got so far:
select
to_char(sysdate, 'yyyy') Time
from
dual;
Which gives me:
TIME
2015
Its working until this point.
I would like to add
if the month is >= 7 I get as output 01.07.current year
if the month is <= 7 I get as output 01.07.(current year - 1 year)
Any ideas how to handle this? I thought about CASE WHEN but I dont get know how.
Thanks!

A simple CASE expression would do the job.
For example,
SQL> SELECT
2 '01.07.' ||
3 CASE
4 WHEN TO_CHAR(SYSDATE, 'MM') < '07'
5 THEN
6 TO_CHAR(SYSDATE, 'YYYY')
7 ELSE
8 TO_CHAR(add_months(SYSDATE,-12), 'YYYY')
9 END case_date
10 FROM dual;
CASE_DATE
----------
01.07.2015
SQL>
To keep it even more precise, you could keep the common value outside the CASE expression:
SQL> SELECT '01.07.'
2 ||
3 CASE
4 WHEN TO_CHAR(SYSDATE, 'MM') < '07'
5 THEN TO_CHAR(SYSDATE, 'YYYY')
6 ELSE TO_CHAR(add_months(SYSDATE,-12), 'YYYY')
7 END case_date
8 FROM dual;
CASE_DATE
----------
01.07.2015
SQL>

Using extract more readable
SELECT
to_date((CASE
WHEN extract(MONTH FROM SYSDATE) >= 7 THEN
0
ELSE
-1
END) + extract(YEAR FROM SYSDATE) || '07-01', 'yyyy-mm-dd') END
FROM dual

Related

convert into date format oracle

I have a field c_days in the table my_table that accepts numeric values ​​from 1 to 31.
In this field, numbers from 1 to 9 are single digits.
I am writing a condition, if c_day is greater than today, then you need to display c_day in the to_date date format, if less, then display c_day in the date format, only the next month.
For example, c_day is 14, and today we have the 8th number, so you need to display the date 14.02.2023, If c_day is equal to 5, then you need to display the date of the next month 05.03.2023
I did something like this:
SELECT
C_DAY,
CASE
WHEN C_DAY >= TO_CHAR(SYSDATE, 'DD') THEN
TO_DATE(C_DAY || '.' || TO_CHAR(SYSDATE, 'MM') || '.' || TO_CHAR(SYSDATE, 'YYYY'), 'dd.mm.yyyy')
WHEN C_DAY < TO_CHAR(SYSDATE, 'DD') THEN
TO_DATE(C_DAY || '.' || TO_CHAR(SYSDATE, 'MM') || '.' || TO_CHAR(SYSDATE, 'YYYY'), 'dd.mm.yyyy')
WHEN C_DAY IS NULL THEN
null
END AS new_field
FROM my_table
The problem is that the end result is not converted to the date format, I thought it's cause of that the dates can be displayed as 1.03.2023, 7.03.2023, so i tried convert it into
TO_CHAR(C_DAY, 'fm00')
and did this:
SELECT
C_DAY,
CASE
WHEN TO_CHAR(C_DAY, 'fm00') >= TO_CHAR(SYSDATE, 'DD') THEN
TO_DATE(TO_CHAR(C_DAY, 'fm00') || '.' || TO_CHAR(SYSDATE, 'MM') || '.' || TO_CHAR(SYSDATE, 'YYYY'), 'dd.mm.yyyy')
WHEN TO_CHAR(C_DAY, 'fm00') < TO_CHAR(SYSDATE, 'DD') THEN
TO_DATE(TO_CHAR(C_DAY, 'fm00') || '.' || TO_CHAR(SYSDATE, 'MM') || '.' || TO_CHAR(SYSDATE, 'YYYY'), 'dd.mm.yyyy')
WHEN C_DAY IS NULL THEN
null
END AS new_field
FROM my_table
But its not even working, it shows ora error
You can do it without any string-to-date (or vice-versa) conversions using:
SELECT C_DAY,
LEAST(
ADD_MONTHS(
TRUNC(SYSDATE, 'MM'),
CASE WHEN c_day <= EXTRACT(DAY FROM SYSDATE) THEN 0 ELSE 1 END
) + c_day - 1,
LAST_DAY(
ADD_MONTHS(
TRUNC(SYSDATE, 'MM'),
CASE WHEN c_day <= EXTRACT(DAY FROM SYSDATE) THEN 0 ELSE 1 END
)
)
) AS new_field
FROM my_table
Which, for the sample data:
CREATE TABLE my_table(c_day) AS
SELECT LEVEL FROM DUAL CONNECT BY LEVEL <= 31;
Outputs:
C_DAY
NEW_FIELD
1
2023-02-01 00:00:00
2
2023-02-02 00:00:00
3
2023-02-03 00:00:00
4
2023-02-04 00:00:00
5
2023-02-05 00:00:00
6
2023-02-06 00:00:00
7
2023-02-07 00:00:00
8
2023-02-08 00:00:00
9
2023-03-09 00:00:00
10
2023-03-10 00:00:00
11
2023-03-11 00:00:00
12
2023-03-12 00:00:00
13
2023-03-13 00:00:00
14
2023-03-14 00:00:00
15
2023-03-15 00:00:00
16
2023-03-16 00:00:00
17
2023-03-17 00:00:00
18
2023-03-18 00:00:00
19
2023-03-19 00:00:00
20
2023-03-20 00:00:00
21
2023-03-21 00:00:00
22
2023-03-22 00:00:00
23
2023-03-23 00:00:00
24
2023-03-24 00:00:00
25
2023-03-25 00:00:00
26
2023-03-26 00:00:00
27
2023-03-27 00:00:00
28
2023-03-28 00:00:00
29
2023-03-29 00:00:00
30
2023-03-30 00:00:00
31
2023-03-31 00:00:00
fiddle
Here's one option:
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> WITH
2 my_table (c_day)
3 AS
4 (SELECT 14 FROM DUAL
5 UNION ALL
6 SELECT 5 FROM DUAL
7 UNION ALL
8 SELECT 30 FROM DUAL)
9 SELECT c_day,
10 TO_DATE (
11 LPAD (LEAST (c_day, TO_CHAR (LAST_DAY (SYSDATE), 'dd')), 2, '0')
12 || '.'
13 || TO_CHAR (
14 CASE
15 WHEN c_day < TO_CHAR (SYSDATE, 'dd')
16 THEN
17 ADD_MONTHS (SYSDATE, 1)
18 ELSE
19 SYSDATE
20 END,
21 'mm.yyyy'),
22 'dd.mm.yyyy') AS result
23 FROM my_table;
C_DAY RESULT
---------- ----------
14 14.02.2023
5 05.03.2023
30 28.02.2023
SQL>
As far as I understand your question, one solution could be this one
SELECT
C_DAY,
CASE
WHEN C_DAY >= TO_CHAR(SYSDATE, 'DD') THEN
ADD_MONTHS(TO_DATE(TO_CHAR(SYSDATE, 'YYYY-MM-')||C_DAY , 'YYYY-MM-DD'), 1)
WHEN C_DAY < TO_CHAR(SYSDATE, 'DD') THEN
TO_DATE(TO_CHAR(SYSDATE, 'YYYY-MM-')||C_DAY , 'YYYY-MM-DD')
END AS new_field
FROM my_table
The ADD_MONTHS function works as this:
If date is the last day of the month or if the resulting month has fewer days than the day component of date, then the result is the last day of the resulting month. Otherwise, the result has the same day component as date.

sql: generate additional dates depending on the period

Got data like this:
date_start
date_end
rate
01.04.2022
20.04.2022
1
21.04.2022
11.05.2022
7
12.05.2022
15.07.2022
5
And i need get separete dates between start\end month, like this:
date_start
date_end
rate
01.04.2022
20.04.2022
1
21.04.2022
30.04.2022
7
01.05.2022
11.05.2022
7
12.05.2022
31.05.2022
5
01.06.2022
30.06.2022
5
01.07.2022
15.07.2022
5
any ideas?
found a solution, everything works correctly on different arrays of dates, but it seems to me that there may be a much simpler and more concise solution for this case?
code below:
select d_surcharge_period_from,
d_surcharge_period_to,
case
when column_value = 1 then
d_surcharge_period_from
when column_value > 1 then
trunc(add_months(d_surcharge_period_from, column_value - 1), 'mm')
end as period_beg,
case
when lead(column_value) over(order by d_surcharge_period_from, column_value) = 1 then
d_surcharge_period_to
else
last_day(add_months(d_surcharge_period_from, column_value - 1))
end period_end,
n_rate_value,
column_value
from (select to_date('01.04.2022', 'dd.mm.yyyy') as d_surcharge_period_from,
to_date('20.04.2022', 'dd.mm.yyyy') as d_surcharge_period_to,
1 n_rate_value,
0 as n_used
from dual
union all
select to_date('21.04.2022', 'dd.mm.yyyy') as d_surcharge_period_from,
to_date('11.05.2022', 'dd.mm.yyyy') as d_surcharge_period_to,
7 n_rate_value,
0 as n_used
from dual
union all
select to_date('12.05.2022', 'dd.mm.yyyy') as d_surcharge_period_from,
to_date('15.07.2022', 'dd.mm.yyyy') as d_surcharge_period_to,
5 n_rate_value,
0 as n_used
from dual),
table(cast(multiset (select level
from dual
connect by add_months(trunc(d_surcharge_period_from, 'MM'), level - 1) <= d_surcharge_period_to) as sys.odcinumberlist))
order by d_surcharge_period_from,
column_value

Conversion of to_date says missing right parenthesis

select A,B,C,
TO_DATE(year ||'-'|| LPAD(month,2,0) ||'-01','YYYY-MM-DD') as firstday,
LAST_DAY(TO_DATE(year ||'-'|| LPAD(month,2,0) ||'-01','YYYY-MM-DD')) as lastday
from test;
Error : "FROM keyword not found where expected"
Whole lot of things.
SQL> with test (year, month) as
2 (select '2022', '4' from dual)
3 select to_date(year ||'-'|| lpad(month, 2, '0') || '-01', 'yyyy-mm-dd') result
4 from test;
RESULT
--------------------
01-APR-22
SQL>
Though, as it seems you want the 1st of that month, you can shorten it to
SQL> with test (year, month) as
2 (select '2022', '4' from dual)
3 select to_date(year || month, 'yyyymm') result
4 from test;
RESULT
--------------------
01-APR-22
SQL>
The LAST_DAY option:
SQL> with test (year, month) as
2 (select '2022', '4' from dual)
3 select
4 to_date(year ||'-'|| lpad(month,2,0) ||'-01','YYYY-MM-DD') as firstday,
5 last_day(to_date(year ||'-'|| lpad(month,2,0) ||'-01','YYYY-MM-DD')) as lastday
6 from test;
FIRSTDAY LASTDAY
---------- ----------
01.04.2022 30.04.2022
SQL>

Database date depending on SYSDATE with a condition

I would like to select and return a number of rows depending on 'today's' date.
Something like...
SELECT * FROM my_table
WHERE
//some conditions AND
my_DATE BETWEEN trunc (sysdate, 'mm')/*current month*/ AND SYSDATE
However I would like to return:
Only rows for the last two months (excluding this month) if today's date 'dd' is less than 15
Return rows for the last two months (including this month) if today's date is >= 15
I am thinking of a case. Something like
WHERE
(CASE
when trunc (sysdate, 'dd') < 15 THEN
TO_CHAR(my_DATE, 'MMYYY') BETWEEN TO_CHAR((add_months(sysdate,-3)) AND TO_CHAR((add_months(sysdate,-1))
Any pointers are highly appreciated as I get acquainted with this arena. Thank you
I would do all the computation on sysdate, to help the optimizer user indexes:
where datecol >= add_months(trunc(sysdate, 'MON'),
(case when extract(day from sysdate) < 15 then -2 else -1 end)
) and
datecol < add_months(trunc(sysdate, 'MON'),
(case when extract(day from sysdate) < 15 then 0 else 1 end)
)
EDIT:
Based on the comment:
where datecol >= add_months(trunc(sysdate, 'MON'), -2) and
datecol < add_months(trunc(sysdate, 'MON'),
(case when extract(day from sysdate) < 15 then 0 else 1 end)
)
If this represents sample data:
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> select * from test order by id;
ID DATUM
---------- ----------
1 20.12.2020
2 07.01.2021
3 15.02.2021
4 25.02.2021
5 10.03.2021
then see whether the following code makes sense. The whole date '&&par_sysdate' shuld be replaced by sysdate in real life; for testing purposes, I used a parameter as sysdate returns today's date.
First example: par_sysdate = 10.03.2021 (day is less than 15):
SQL> select t.id, t.datum
2 from test t
3 where t.datum >=
4 trunc(add_months(date '&&par_sysdate',
5 -case when to_number(to_char(date '&&par_sysdate', 'dd')) < 15 then 2
6 else 1
7 end
8 ), 'mm')
9 and t.datum < case when to_number(to_char(date '&&par_sysdate', 'dd')) < 15 then
10 trunc(date '&&par_sysdate', 'mm')
11 else date '&&par_sysdate'
12 end;
Enter value for par_sysdate: 2021-03-10
ID DATUM
---------- ----------
2 07.01.2021
3 15.02.2021
4 25.02.2021
Second example: using today's date (20.03.2021) where day is greater than 15:
SQL> undefine par_sysdate
SQL> /
Enter value for par_sysdate: 2021-03-20
ID DATUM
---------- ----------
3 15.02.2021
4 25.02.2021
5 10.03.2021
SQL>
Or, as I said, using sysdate:
SQL> select t.id, t.datum
2 from test t
3 where t.datum >=
4 trunc(add_months(sysdate,
5 -case when to_number(to_char(sysdate, 'dd')) < 15 then 2
6 else 1
7 end
8 ), 'mm')
9 and t.datum < case when to_number(to_char(sysdate, 'dd')) < 15 then
10 trunc(sysdate, 'mm')
11 else sysdate
12 end;
ID DATUM
---------- ----------
3 15.02.2021
4 25.02.2021
5 10.03.2021
SQL>
Your requirements are not wholly clear, but I think you want something like this:
select t.*
from mytable t
where (to_number(to_char(sysdate, 'dd')) < 15
and t.dt >= add_months(trunc(sysdate, 'mm'),-3)
and t.dt < trunc(sysdate, 'mm')
)
or (to_number(to_char(sysdate, 'dd')) >= 15
and t.dt >= add_months(trunc(sysdate, 'mm'),-2)
and t.dt <= last_day(sysdate)
)
I have put a demo version of this code on db<>fiddle with an affordance for changing the date of today instead of using sysdate.
the previous months should be FULL not previous months based on today's date.
To get full months, truncate the date using the 'mm' mask, which returns the first of the month.

How to find number of Sundays in a given year (ex: input_year = 1996) and also the dates of those Sundays

How to find number of Sundays in a given year in Oracle SQL.
Input: 1996
Expected output:
<date-of-sunday-1>
<date-of-sunday-2>
.............
.............
<date-of-sunday-n>
<count-of-no-of-sundays-in-that-year>
This is how to fetch Sundays:
SQL> with the_whole_year as
2 (select trunc(to_date(&&par_year, 'yyyy'), 'yyyy') + level - 1 c_date,
3 to_char(trunc(to_date(&&par_year, 'yyyy'), 'yyyy') + level - 1, 'fmday') c_day
4 from dual
5 connect by level <= add_months(trunc(to_date(&&par_year, 'yyyy'), 'yyyy'), 12) -
6 trunc(to_date(&&par_year, 'yyyy'), 'yyyy')
7 )
8 select c_date
9 from the_whole_year
10 where c_day = 'sunday';
C_DATE
----------
07.01.1996
14.01.1996
21.01.1996
28.01.1996
04.02.1996
11.02.1996
<snip>
I suppose you'll be able to count them yourself.
[EDIT: a function that does the counting]
SQL> CREATE OR REPLACE FUNCTION f_count_of_sundays (par_year IN NUMBER)
2 RETURN NUMBER
3 IS
4 retval NUMBER;
5 BEGIN
6 WITH the_whole_year
7 AS ( SELECT TRUNC (TO_DATE (par_year, 'yyyy'), 'yyyy') + LEVEL - 1
8 c_date,
9 TO_CHAR (
10 TRUNC (TO_DATE (par_year, 'yyyy'), 'yyyy') + LEVEL - 1,
11 'fmday')
12 c_day
13 FROM DUAL
14 CONNECT BY LEVEL <=
15 ADD_MONTHS (
16 TRUNC (TO_DATE (par_year, 'yyyy'), 'yyyy'),
17 12)
18 - TRUNC (TO_DATE (par_year, 'yyyy'), 'yyyy'))
19 SELECT COUNT (*)
20 INTO retval
21 FROM the_whole_year
22 WHERE c_day = 'sunday';
23
24 RETURN retval;
25 END;
26 /
Function created.
SQL> select f_count_of_sundays(1996) from dual;
F_COUNT_OF_SUNDAYS(1996)
------------------------
52
SQL>