How to get Year/Week according to ISO? - sql

I have the below code, which gives week 202153. However, I would need to have, instead of the first week of year 2021 as 202153, as 202053.
Is there any built-in functionality to address this?
SELECT
to_char(TO_DATE('20210104', 'YYYYMMDD') - 3, 'YYYYIW') AS yearweek
FROM
dual
Expected output: 202053. I could simply decode the value, but I'm hoping for a more robust solution for future years.

Use IYYY (ISO-year) rather than the YYYY (calendar year) format model.
SELECT TO_CHAR( DATE '2021-01-04' - 3, 'IYYYIW') AS yearweek
FROM DUAL
Which outputs:
YEARWEEK
202053
db<>fiddle here

Related

Oracle : Query to get the Last Friday of the week if I give any date

If I give a date let's say '13-Mar-2019' my query needs to retrieve the value '15-Mar-2019'. Which is the last Friday of the week.
Trancate the date to the ISO week, which gets you the week's Monday (as an ISO week starts with Monday). Then add four days:
select trunc(date '2019-03-13', 'iw') + 4 from dual;
I would use next_day(). It is the Oracle function specifically designed for this purpose.
select next_day(date '2019-03-13', 'Fri')
from dual;
The only nuance is that if the date is Friday, then it will return the next Friday. That might be what you want. Otherwise, just subtract one day:
select next_day(date '2019-03-13' - 1, 'Fri') as friday_end_of_week
from dual;
Try below -
select trunc(to_date('13-Mar-2019'), 'iw') + 4 from dual
SELECT NEXT_DAY( to_date('2019-03-13', 'yyyy-mm-dd'), to_char(to_date('2019-03-01', 'yyyy-mm-dd'), 'DAY')) FROM dual;
demo

Oracle SQL Create Date from Parts

I have two date fields in a database called "EFFECTIVE_DATE" and "POINT_DATE"
How do I create a new date field, where the date is made up from the year of "EFFECTIVE_DATE", the month of "POINT_DATE" and the day of "POINT_DATE" ?
I would normally use Datefromparts, but this is an Oracle Database not Microsoft
Kind Regards
Here's an approach using ADD_MONTHS and EXTRACT(YEAR FROM ....). You simply add or subtract the needed number of months (always a multiple of 12, since you are only changing the year). Unlike the TO_CHAR / TO_DATE solutions, this approach handles leap days (Feb. 29). On the other hand, be advised that changing the date from 28 Feb. 2003 to the year 2012 will change it to Feb. 29 (ADD_MONTHS changes the last day of a month to the last day of the resulting month).
with
inputs as (
select date '2013-03-22' as effective_date,
date '2017-08-14' as point_date
from dual
)
-- end of TEST data (do not include in the solution!)
select effective_date, point_date,
add_months(point_date, 12 * ( extract (year from effective_date) -
extract (year from point_date) )
) as mixed_date
from inputs;
EFFECTIVE_DATE POINT_DATE MIXED_DATE
-------------- ---------- ----------
03/22/2013 08/14/2017 08/14/2013
Hmmm . . . this produces a nice string in the YYYY-MM-DD format:
select to_char(effective_date, 'YYYY') || '-' || to_char(point_date, 'MM-DD')
And this parses it back to a date:
select to_date(to_char(effective_date, 'YYYY') || '-' || to_char(point_date, 'MM-DD'), 'YYYY-MM-DD')
Note: You might want to be careful about Feb 29th.
Assuming all coulmns are DATE data types, you can use this one
TO_DATE(TO_CHAR(EFFECTIVE_DATE, 'YYYY') || TO_CHAR(POINT_DATE, 'MMDD'), 'YYYYMMDD')
Be aware of leap years!

How to convert a sysdate month value to number in oracle?

Im trying to return the CARDS of my CARD table that will expire in the next month. But the problem is that the table has two columns to represent the card date. The columns are EXPIREDAY and EXPIREMONTH ,both are numbers. So when i do that query i get an error:
select * from CARD WHERE EXPIREDAY <= sysdate - interval '2' DAY;
//Oracle error: ORA-00932: inconsistent datatypes: expected NUMBER got DATE
Is there a way to convert the sysdate - interval '2' DAY as Number data type?
Thanks!
If you want to compare the values as strings you can use this to convert the SYSDATE
SELECT TO_CHAR(sysdate, 'MM') || TO_CHAR(sysdate, 'DD') MONTH_NUM FROM DUAL
-- gives you "0922"
and this for your numeric columns which will pad with leading zeros if you only have a single digit
SELECT TO_CHAR(9, 'FM00') || TO_CHAR(22, 'FM00') MONTH_NUM FROM DUAL
-- also gives you "0922"
If you have control over the table schema it would be best practise to store both the DAY and MONTH values in a single numeric field, so that 9-SEP would be stored in this column as the numeric value 0922 where the month is first so that the natural ordering is used.
A simple and not necessarily very efficient approach is to convert the day and month values into an actual date, using to_date(), and then compare that with your target date range:
select * from card
where to_date(lpad(expireday, 2, '0')
||'/'|| lpad(expiremonth, 2, '0'), 'DD/MM')
between sysdate and add_months(sysdate, 1);
Which appears to work. But this will have problems if the dates span the end of the year. Because your table doesn't specify the year, you either have to work one out, or allow to_date to default it to the current year. And if you let it default then it won't work. For example, if you have values for December and January in your table, and run this query in December, then the January dates will be seen as January 2014, and won't be counted as being in the next month. So you'll need to do more to pick the right year.
This treats any month numbers before the current one as being next year, which may be good enough for you as you only have a one-month window:
select * from card
where to_date(lpad(expireday, 2, '0')
||'/'|| lpad(expiremonth, 2, '0')
||'/'|| (extract(year from sysdate) +
case when expiremonth < extract(month from sysdate) then 1 else 0 end),
'DD/MM/YYYY')
between sysdate and add_months(sysdate, 1);
SQL Fiddle using a date range from December to January.
And you can see the ways the two columns are being combined to form a date in this Fiddle.
As so often, the moral is... store things as the right data type. Store dates as dates, not as string or numbers.
Im trying to return the CARDS of my CARD table that will expire in the next month. But the problem is that the table has two columns to represent the card date.
Assuming:
you are using floating months (say: from 23 dec. to 23 jan.) and
your table somehow only contains one (floating ?) year of data
Why can't you use simple arithmetics? Like that:
-- some constant definitions for testing purpose
with cst as (
select EXTRACT(DAY from TO_DATE('23/12','DD/MM')) as theDay,
EXTRACT(MONTH from TO_DATE('23/12','DD/MM')) as theMonth
from dual)
-- the actual query
select card.* from card,cst
where (expiremonth = theMonth AND expireday > theDay)
or (expiremonth = 1+MOD(theMonth,12) AND expireday <= theDay);
-- ^^^^^^^^^^^^^^^^^^
-- map [01 .. 12] to [02 .. 12, 01] (i.e.: next month)
This will simply select all "pseudo-dates" from tomorrow to the end of the month, as well as any one before (and including) the current day# next month.
See this example.
For something a little bit more generic, but probably more efficient than converting all your values TO_DATE, you might want to try that:
-- the calendar is the key part of the query (see below)
with calendar as (
select extract(month from sysdate + level) as theMonth,
extract(day from sysdate + level) as theDay
from DUAL connect by ROWNUM <= 8)
-- ^
-- adjust to the right number of days you are looking for
select card.* from card join calendar
on expiremonth = theMonth and expireDay = theDay
The idea here is to simply build a calendar with all the upcoming days and then join your data table on that calendar. See an example here.
Try using to_char(sysdate - interval '2' DAY,'ddmmyyyy') to convert to character type. The date format('ddmmyyyy') will depend of the value of expiredate

Retrieve number of the day sql query

I wan't to retrieve the number of the day using an SQL request but I found that I retrieve the number of day since the 01-01-4712 using this query:
SELECT TO_CHAR(TRUNC(SYSDATE),'J') FROM DUAL;
Is there any other query I may use?
Use to_char() to convert your date. Format mask 'DDD' returns the day of the year.
select to_char(sysdate, 'DDD') from dual;
select to_char(to_date('1/1/2014', 'MM/DD/YYYY'), 'DDD') from dual;
Some more info on various formats: http://www.techonthenet.com/oracle/functions/to_char.php
After investigations I found that we can use this query to obtain the number of day in the current year:
select to_date(sysdate) - trunc(sysdate,'YYYY') from dual

Oracle Julian day of year

how can I select Julian day of year in Oracle database?
I tried:
select to_char(sysdate, 'J') from dual;
Which gives me the number of days since January 1, 4712 BC. But I would need the number of days since 1.1. of current year.
If you check the TO_CHAR (datetime) documentation you get a link to "Format Models" with a comprehensive list of available formats. I guess you want this:
DDD Day of year (1-366)
SELECT TO_CHAR(SYSDATE, 'DDD') from DUAL;
One way would be to use:
select sysdate - trunc(sysdate,'yyyy') from dual
'Trunc' cuts everything except the year and returns 01/01/2014, subtracted by the sysdate returns numbers of days since 1st of january.
Use sql select trunc(sysdate)+1 - trunc(sysdate,'yyyy') from dual. you will get an even number