简体   繁体   中英

Oracle SQL - Fiscal Week of Year

I want to calculate the Fiscal Week of the Year with the following rules:

  • The fiscal year always starts on June/01
  • The week always starts on Sunday
  • Samples are provided for 2019 but ideally it should work for any year

A few samples of correct values are provided with the screenshot attached

I tried to do something like TO_NUMBER(TO_CHAR(TO_DATE(DATE_ID + 1,'DD-Mon-YY'),'IW')) -21 but towards the end of the Calendar year I start to get negatives

SELECT
    DATE_ID
    , WEEK_OF_YEAR
FROM DATE_DIM
WHERE
    DATE_ID IN
    (
        20190601
        , 20190602
        , 20190915
        , 20191228
        , 20191229
        , 20200101
        , 20200601
        , 20200606
        , 20200607
    )
ORDER BY DATE_ID ASC
;

出于说明目的硬编码的屏幕截图中的值

SELECT TO_CHAR(ADD_MONTHS(SYSDATE,+7),'IW')
  FROM dual

Or in your case,

SELECT date_id,TO_CHAR(ADD_MONTHS(TO_DATE(date_id,'YYYYMMDD'),+7),'IW') week_of_year
  FROM date_dim

If you don't like the ISO dating where week 1 is the week beginning Sunday during which the 1st of the year falls, you can try offsetting it by moving it back to the previous sunday (TRUNC(..,'D'), then advance a week, then add the 7 months. See if this works for you:

SELECT date_id, TO_CHAR(ADD_MONTHS(TRUNC(date_id,'D') + 7,7),'IW') week_of_year
  FROM date_dim

You got confused with your date formats ('yyyymmdd' vs. 'DD-Mon-YY'), so I am using a real date (mydate) in my answer. Convert your string or number to a proper date and you are there:-)

The important thing is to check whether your date is >= June 1. Once this is done you can subtract that year's June 1 or the previous year's one. Well, more or less:-)

select 
  mydate,
  to_char(mydate, 'DY') as tag,
  trunc
  (
    case when to_char(mydate, 'mmdd') >= '0601' then
      trunc(mydate + 1, 'iw') + 6 - to_date(to_char(mydate, 'yyyy') || '0601', 'yyyymmdd')
    else
      trunc(mydate + 1, 'iw') + 6 - to_date(to_char(extract(year from mydate) - 1) || '0601', 'yyyymmdd')
    end / 7
  ) + 1 as fiscal_week
from ...
order by mydate;

Demo: https://dbfiddle.uk/N5pX_5cV

UPDATED ANSWER
You can try this - provide the date like 31-MAY-19 to start your calendar from 01-JUN-19 and define how many days you want. There is a shift of 5 months as the code was taken from my regular calendar and adjusted the start of week to sunday...Tested OK for periods up to 2 years per run. So if you want 6 years you'll have to run this 3 times...

WITH 
        base_calendar AS
            (
                SELECT CurrDate         AS Day_ID,
                TO_CHAR(CurrDate,'Day') AS Week_Day_Full,
                TO_CHAR(CurrDate,'DY')  AS Week_Day_Short,
                TO_NUMBER(TRIM(leading '0' FROM TO_CHAR(CurrDate,'D'))) AS Day_Num_of_Week,
                --
                MAX(CASE WHEN To_Char(CurrDate, 'ddmm') = '2902' THEN EXTRACT(YEAR From CurrDate) END) OVER(Order By CurrDate Rows Between Unbounded Preceding And Current Row) AS last_leap_year,
                Count(CASE WHEN (   TO_CHAR(CurrDate,'DY') = 'SUN' And 
                                    CurrDate Between To_date('01.06.' || To_Char(EXTRACT(YEAR From CurrDate)), 'dd.mm.yyyy') And To_date('31.05.' || To_Char(EXTRACT(YEAR From CurrDate) + 1), 'dd.mm.yyyy')  )
                                OR
                                 (   TO_CHAR(CurrDate,'DY') = 'SUN' And 
                                    CurrDate Between To_date('01.06.' || To_Char(EXTRACT(YEAR From CurrDate) - 1), 'dd.mm.yyyy') And To_date('31.05.' || To_Char(EXTRACT(YEAR From CurrDate)  ), 'dd.mm.yyyy')  )
                          THEN 1 
                      END) OVER(Order By CurrDate Rows Between Unbounded Preceding And Current Row) AS cnt_sundays
              FROM
                (
                    SELECT level n,
                        -- Calendar starts at the day after this date
                        TO_DATE('31/05/2019','DD/MM/YYYY') + NUMTODSINTERVAL(level,'DAY') CurrDate
                    FROM dual
                        -- Change for the number of days to be added to the table.
                    CONNECT BY level <= 731
                )
            )
SELECT  DISTINCT
      day_id,
      CASE  WHEN  (cnt_sundays + 1 ) - ( (EXTRACT(YEAR From Add_Months(Day_id, - 5)) -EXTRACT(YEAR From MIN(Day_id) OVER()) ) * 53) >= 54 THEN 1
            WHEN EXTRACT(YEAR From day_id) <> last_leap_year And day_id > = To_Date('01.06.' || To_Char(EXTRACT(YEAR From day_id)), 'dd.mm.yyyy' ) 
                THEN (cnt_sundays + 1)  - ( (EXTRACT(YEAR From Add_Months(Day_id, - 5)) -EXTRACT(YEAR From MIN(Day_id) OVER()) ) * 53) + 1
      ELSE (cnt_sundays + 1) - ( (EXTRACT(YEAR From Add_Months(Day_id, - 5)) -EXTRACT(YEAR From MIN(Day_id) OVER()) ) * 53) 
      END week_of_year,
      --
        week_day_full,
        week_day_short,
        CASE week_day_short   
            WHEN 'SUN' THEN 1
            WHEN 'MON' THEN 2
            WHEN 'TUE' THEN 3
            WHEN 'WED' THEN 4
            WHEN 'THU' THEN 5
            WHEN 'FRI' THEN 6
            WHEN 'SAT' THEN 7
    END AS day_num_of_week
FROM base_calendar
ORDER BY day_id

R ESULTS:

DAY_ID    WEEK_OF_YEAR WEEK_DAY_FULL WEEK_DAY_SHORT DAY_NUM_OF_WEEK
--------- ------------ ------------- -------------- ---------------
01-JUN-19            1 Saturday      SAT                          7 
02-JUN-19            2 Sunday        SUN                          1 
03-JUN-19            2 Monday        MON                          2 
04-JUN-19            2 Tuesday       TUE                          3 
05-JUN-19            2 Wednesday     WED                          4
... ...
... ...
13-SEP-19           16 Friday        FRI                          6 
14-SEP-19           16 Saturday      SAT                          7 
15-SEP-19           17 Sunday        SUN                          1 
16-SEP-19           17 Monday        MON                          2
... ...
30-DEC-19           32 Monday        MON                          2 
31-DEC-19           32 Tuesday       TUE                          3 
01-JAN-20           32 Wednesday     WED                          4 
02-JAN-20           32 Thursday      THU                          5 
...
27-FEB-20           40 Thursday      THU                          5 
28-FEB-20           40 Friday        FRI                          6 
29-FEB-20           40 Saturday      SAT                          7 
01-MAR-20           41 Sunday        SUN                          1 
02-MAR-20           41 Monday        MON                          2
...
29-MAY-20           53 Friday        FRI                          6 
30-MAY-20           53 Saturday      SAT                          7 
31-MAY-20            1 Sunday        SUN                          1 
01-JUN-20            1 Monday        MON                          2 
02-JUN-20            1 Tuesday       TUE                          3 
03-JUN-20            1 Wednesday     WED                          4 
04-JUN-20            1 Thursday      THU                          5 
05-JUN-20            1 Friday        FRI                          6 
06-JUN-20            1 Saturday      SAT                          7 
07-JUN-20            2 Sunday        SUN                          1
...  ...
...  ...
22-MAY-21           51 Saturday      SAT                          7 
23-MAY-21           52 Sunday        SUN                          1 
24-MAY-21           52 Monday        MON                          2 
25-MAY-21           52 Tuesday       TUE                          3 
26-MAY-21           52 Wednesday     WED                          4 
27-MAY-21           52 Thursday      THU                          5 
28-MAY-21           52 Friday        FRI                          6 
29-MAY-21           52 Saturday      SAT                          7 
30-MAY-21           53 Sunday        SUN                          1 
31-MAY-21           53 Monday        MON                          2 

 731 rows selected 

... with year 2025 - part of the result mentioned in comments above...

... ...
29-MAY-25           53 Thursday      THU                          5 
30-MAY-25           53 Friday        FRI                          6 
31-MAY-25           53 Saturday      SAT                          7 
01-JUN-25            1 Sunday        SUN                          1 
02-JUN-25            1 Monday        MON                          2 
03-JUN-25            1 Tuesday       TUE                          3 
04-JUN-25            1 Wednesday     WED                          4 
05-JUN-25            1 Thursday      THU                          5 
06-JUN-25            1 Friday        FRI                          6 
07-JUN-25            1 Saturday      SAT                          7 
08-JUN-25            2 Sunday        SUN                          1 
... ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM