Friday, November 25, 2011

Generate schedule data in SQL Server







CREATE TABLE ScheduleMaster
(
    rcrPK                int NOT NULL PRIMARY KEY,
    rcrName                varchar(500) NOT NULL,
    rcrStartDate        date NOT NULL,
    rcrEndDate            date NULL,
    rcrPatternType        tinyint NOT NULL,
    rcrPattern            varchar(5000) NULL,
    rcrInterval            int NOT NULL,
    rcrDayOfMonth        int NOT NULL,
    rcrWeekNo            int NOT NULL,
    rcrDayNo            int NOT NULL,
    rcrMonthOfYear        varchar(50) NULL,
    rcrDayOfYear        int NOT NULL,
    rcrTimeOccurence    time(7) NOT NULL,
    rcrNoOfOccurence    int NULL,
    rcrActive            tinyint NOT NULL
)

GO

INSERT [dbo].[ScheduleMaster] ([rcrPK], [rcrName],  [rcrStartDate], [rcrEndDate], [rcrPatternType], [rcrPattern], [rcrInterval], [rcrDayOfMonth], [rcrWeekNo], [rcrDayNo], [rcrMonthOfYear], [rcrDayOfYear], [rcrTimeOccurence], [rcrNoOfOccurence], [rcrActive])
VALUES (1, N'Yearly wise Schedule with First pattern',  CAST(0x07240B00 AS Date), CAST(0xAE400B00 AS Date), 4, NULL, 2, 0, 0, 0, N'01,05,10', 25, CAST(0x07004EB119B90000 AS Time), 0,1)

INSERT [dbo].[ScheduleMaster] ([rcrPK], [rcrName],  [rcrStartDate], [rcrEndDate], [rcrPatternType], [rcrPattern], [rcrInterval], [rcrDayOfMonth], [rcrWeekNo], [rcrDayNo], [rcrMonthOfYear], [rcrDayOfYear], [rcrTimeOccurence], [rcrNoOfOccurence], [rcrActive])
VALUES (2, N'Yearly wise Schedule with Second pattern',  CAST(0x07240B00 AS Date), CAST(0xAE400B00 AS Date), 4, NULL, 2, 0, 2, 3, N'01,05,10', 0, CAST(0x07004EB119B90000 AS Time), 0,1)

INSERT [dbo].[ScheduleMaster] ([rcrPK], [rcrName],  [rcrStartDate], [rcrEndDate], [rcrPatternType], [rcrPattern], [rcrInterval], [rcrDayOfMonth], [rcrWeekNo], [rcrDayNo], [rcrMonthOfYear], [rcrDayOfYear], [rcrTimeOccurence], [rcrNoOfOccurence], [rcrActive])
VALUES (3, N'Monthly Schedule with First pattern',  CAST(0x15240B00 AS Date), CAST(0xED410B00 AS Date), 3, NULL, 1, 8, 0, 0, NULL, 0, CAST(0x07004EB119B90000 AS Time), 0, 1)

INSERT [dbo].[ScheduleMaster] ([rcrPK], [rcrName],  [rcrStartDate], [rcrEndDate], [rcrPatternType], [rcrPattern], [rcrInterval], [rcrDayOfMonth], [rcrWeekNo], [rcrDayNo], [rcrMonthOfYear], [rcrDayOfYear], [rcrTimeOccurence], [rcrNoOfOccurence], [rcrActive])
VALUES (4, N'Monthly Schedule with Second pattern',  CAST(0x15240B00 AS Date), CAST(0xED410B00 AS Date), 3, NULL, 3, 0, 3, 4, NULL, 0, CAST(0x07004EB119B90000 AS Time), 0, 1)

INSERT [dbo].[ScheduleMaster] ([rcrPK], [rcrName],  [rcrStartDate], [rcrEndDate], [rcrPatternType], [rcrPattern], [rcrInterval], [rcrDayOfMonth], [rcrWeekNo], [rcrDayNo], [rcrMonthOfYear], [rcrDayOfYear], [rcrTimeOccurence], [rcrNoOfOccurence], [rcrActive])
VALUES (5, N'Weekly Schedule',  CAST(0x07240B00 AS Date), CAST(0xCC400B00 AS Date), 2, N'MON,FRI', 1, 0, 0, 0, NULL, 0, CAST(0x07004EB119B90000 AS Time), 0, 1)

INSERT [dbo].[ScheduleMaster] ([rcrPK], [rcrName],  [rcrStartDate], [rcrEndDate], [rcrPatternType], [rcrPattern], [rcrInterval], [rcrDayOfMonth], [rcrWeekNo], [rcrDayNo], [rcrMonthOfYear], [rcrDayOfYear], [rcrTimeOccurence], [rcrNoOfOccurence], [rcrActive])
VALUES (6, N'Daily Schedule',  CAST(0x07240B00 AS Date), CAST(0x90400B00 AS Date), 1, NULL, 1, 0, 0, 0, NULL, 0, CAST(0x07004EB119B90000 AS Time), 0,1)

INSERT [dbo].[ScheduleMaster] ([rcrPK], [rcrName],  [rcrStartDate], [rcrEndDate], [rcrPatternType], [rcrPattern], [rcrInterval], [rcrDayOfMonth], [rcrWeekNo], [rcrDayNo], [rcrMonthOfYear], [rcrDayOfYear], [rcrTimeOccurence], [rcrNoOfOccurence], [rcrActive])
VALUES (7, N'Custom Schedule',  CAST(0x07240B00 AS Date), CAST(0x90400B00 AS Date), 5, N'01-JAN-2011,08-JAN-2011,10-JAN-2011,05-OCT-2013', 1, 0, 0, 0, NULL, 0, CAST(0x07004EB119B90000 AS Time), 0, 1)

GO

Create Procedure dbo.spGetSchedule
(
    @FromDt            Date ,
    @ToDt            Date
)
As
Begin

    Set Nocount On;
    --// Temporary table for handle final result.
    Declare @tmp Table
    (
        dt                DateTime not null,
        Name            Varchar(500) not null
    )
    --// Declaration section
    Declare
         -- Variables for Cursor looping
        @Name            Varchar(500),   
        @StartDate        Datetime,
        @EndDate        Datetime,
        @PatternType    TinyInt,
        @Pattern        Varchar(5000),
        @Interval        Int, -- Interval period
        @DayOfMonth        Int, -- Monthwise scheduling on which day.
        @WeekNo            Int, -- Month/Year wise Second pattern, indicates which week 1'st,2'nd,3'rd,4'th
        @DayNo            Int,  -- Sunday - 1,Monday - 2,Tuesday - 3,Wednesday -4,Thursday - 5,FrNameay - 6,Saturday - 7
        @MonthOfYear    Varchar(50), -- Year wise scheduling on which month , 1-Jan,2-Feb.. etc.
        @DayOfYear        Int, -- Year wise scheduling on which month of day
        @TimeOccurence    Time,
        @NoOfOccurence    TinyInt,
    ------------------------------
    -- Variables for Prgm flow
        @firstofmonth    Datetime, -- Optional variable  for taking first date of the month in pgrm flow
        @CurDate        Datetime,    -- Optional variable  for taking date in pgrm flow   
        @Pos            Int = 0, -- To keep Position of week or Custom type.
        @intYearMonth    Int, --for take month value from month pattern in year wise shedule.
    -------------------------------
        -- Code pending using with following variable
        @LastOccurence    Int,
        @LastProcessed    Datetime
    -------------------------------

    Declare Cur Cursor Fast_Forward Read_Only For
        Select
             rcrName   
            ,rcrStartDate   
            ,rcrEndDate       
            ,rcrPatternType   
            ,rcrPattern       
            ,rcrInterval       
            ,rcrDayOfMonth   
            ,rcrWeekNo       
            ,rcrDayNo       
            ,rcrMonthOfYear   
            ,rcrDayOfYear   
            ,rcrTimeOccurence
            ,rcrNoOfOccurence
        From ScheduleMaster Where
        (
            (@FromDt        Between rcrStartDate    And rcrEndDate) Or
            (@ToDt            Between rcrStartDate    And rcrEndDate) Or
            (rcrStartDate    Between @FromDt            And @ToDt) Or
            (rcrEndDate        Between @FromDt            And @ToDt)
        ) And (rcrActive = 1)
    Open Cur
    Fetch Next From Cur Into
                             @Name           
                            ,@StartDate       
                            ,@EndDate       
                            ,@PatternType   
                            ,@Pattern       
                            ,@Interval       
                            ,@DayOfMonth       
                            ,@WeekNo           
                            ,@DayNo           
                            ,@MonthOfYear   
                            ,@DayOfYear       
                            ,@TimeOccurence   
                            ,@NoOfOccurence   

    While @@FETCH_STATUS <> -1
    Begin
        If @StartDate    < @FromDt    Set @StartDate    = @FromDt
        If @EndDate        > @ToDt        Set @EndDate    = @ToDt
       
        --// Main loop schedule.
        While (@StartDate <= @EndDate)
        Begin
            If @PatternType = 5 --// Custom option
            Begin
                If Cast(@StartDate As Date) = Cast(substring(@Pattern,@Pos + 1,11) As Date) --// if date matching with given custom date.
                Begin
                    Insert Into @tmp Select @StartDate,@Name
                   
                    Set @Pos = @Pos + 12 --// increasing position.
                End
                Set @StartDate = DATEADD(day,1,@StartDate) --// Adding oneday day with current date.
            End
            Else If @PatternType = 4 --// Year wise schedule
            Begin
                --if DATEADD(YEAR,@interval,@StartDate) <= @EndDate -- Next date less than current date
                --begin   
                    If /*@MonthOfYear <> 0 and */ @DayOfYear > 0 --// First pattern for year shedule -- Every fixed month & Date
                    Begin
                        --// Logic:
                        --    Date set to first date of the current year then adding with given month and date.
                        -- Eg, '15 nov 2011' => '01 jan 2011' => given month march (3), => '01 mar 2011' => given Day 20 => '20 Mar 2011'
                        While (@Pos <= Len(@MonthOfYear))
                        Begin
                            Set @intYearMonth = Cast(Substring(@MonthOfYear,@Pos + 1,2) As Int)
                            Set @CurDate = Dateadd(Month,0,Dateadd(Day,@DayOfYear-1,Dateadd(Month,@intYearMonth-1,Dateadd(Month,-Month(Dateadd(Day,-Day(@StartDate)+1,@StartDate))+1,Dateadd(Day,-Day(@StartDate)+1,@StartDate)))))
                           
                            If @CurDate > @EndDate Break -- // Some time date will over come given end date so that time we want to break up the postion loop.
                           
                            Insert Into @tmp Values(@CurDate,@Name)
                           
                            Set @Pos = @Pos + 3
                            Set @StartDate = Dateadd(Day,1,@CurDate) --// Adding oneday day with current date.
                        End
                    End
                    Else
                    Begin
                        --// Logic:
                        -- In first Step, Date set to first date of the current month of year.
                        -- Eg, '15 nov 2011' => '01 nov 2011'
                        While (@Pos <= Len(@MonthOfYear))
                        Begin                       
                            Set @intYearMonth = Cast(Substring(@MonthOfYear,@Pos + 1,2) As Int)
                            Set @firstofmonth = Dateadd(Day,@DayOfYear,Dateadd(Month,@intYearMonth-1,Dateadd(Month,-Month(Dateadd(Day,-Day(@StartDate)+1,@StartDate))+1,Dateadd(Day,-Day(@StartDate)+1,@StartDate))))
                            --// Second Step, add requested week with '01 nov 2011' -- Suppose 2'nd weeek then (2-1) * 7 => 7 with '01 nov 2011' then => date will be '08 nov 2011'
                           
                            --// Third step ,No of days to add = (7 + which day (Sunday - 1,Monday - 2,Tuesday - 3,Wednesday -4,Thursday - 5,FrNameay - 6,Saturday - 7) - Weekday Of first date) % 7 with second step result.
                           
                            -- Second week of monday november month -- 2(monday)
                            -- Eg, '08 nov 2011' + ((7+2) -  3) = 9-3 = 6%7 = 6 = '14 nov 2011' Second monday
                            Select @CurDate = Dateadd(Day,((7+@DayNo)-Datepart(DW,t.mydate))%7,t.mydate) From
                                    (Select Dateadd(Day,(@WeekNo-1)*7 ,@firstofmonth) As mydate )t

                            If @CurDate > @EndDate Break -- // Some time date will over come given end date so that time we want to break up the postion loop.
                                   
                            Insert Into @tmp Values(@CurDate,@Name)
                           
                            Set @Pos = @Pos + 3
                            Set @StartDate = Dateadd(Day,1,@CurDate) --// Adding oneday day with current date.
                        End
                    End
                --end
                --// Setting added month as current month for next process
                Set @StartDate = Dateadd(Year,@interval,Dateadd(Day,-Day(@StartDate)+1,Dateadd(Month,-Month(@StartDate)+1,@StartDate)))
                Set @Pos = 0
            End
            Else If @PatternType = 3 --// Month wise schedule
            Begin
                --insert into @tmp Select DATEADD(MONTH,@interval,@StartDate),@Name
                If @DayOfMonth = 0
                Begin
                    --// year wise second pattern formula logic used.
                    Select @firstofmonth = Dateadd(Day,-Day(@StartDate)+1,@StartDate)
                   
                    Select @CurDate = Dateadd(Day,((7+@DayNo)-Datepart(DW,t.mydate))%7,t.mydate) From
                            (Select Dateadd(Day,(@WeekNo-1)*7 ,@firstofmonth) As mydate )t
                   
                    If     @CurDate <= @EndDate                                           
                        Insert Into @tmp values (@CurDate,@Name)
                End
                Else
                Begin
                    --// current date take as first date of the month and add with given day.
                    Set @CurDate = Dateadd(Day,@DayOfMonth-1,Dateadd(Day,-Day(@StartDate)+1,@StartDate))
                    If     @CurDate <= @EndDate
                        Insert Into @tmp Select @CurDate,@Name
                End
                If @DayOfMonth > 0
                Begin
                    Set @StartDate = Dateadd(Month,@interval,@CurDate)
                End
                Else
                Begin
                    Set @StartDate = Dateadd(Month,@interval,Dateadd(Day,-Day(@StartDate)+1,@StartDate))
                End
            End   
            Else If @PatternType = 1 --// Day wise schedule
            Begin
                If @StartDate <= @EndDate
                Begin   
                --// simple logic -- day add with current date considering interval period.
                    Insert Into @tmp Select @StartDate,@Name
                End
                Set @StartDate = Dateadd(Day,@interval,@StartDate)
            End   
            Else If @PatternType = 2  --// Week wise schedule
            Begin
                While (@Pos <= Len(@Pattern))    --// looping Position less than  given week type.
                Begin
                    If @StartDate > @EndDate Break -- // Some time date will over come given end date so that time we want to break up the postion loop.

                    If Left(Upper({fn Dayname (@StartDate)}),3) = Substring(@Pattern,@Pos + 1,3) --// if day character of the current month matching with given week string.
                    Begin
                        If @Pos = 0 Set @CurDate = @StartDate
                       
                        Insert Into @tmp Select @StartDate,@Name
                       
                        Set @Pos = @Pos + 4 --// increasing position.
                    End
                   
                    Set @StartDate = Dateadd(Day,1,@StartDate)
                End
                 Set @StartDate = Dateadd(Week,@interval,@CurDate)
                 Set @Pos = 0 --// We need to clear the position for next level loop.
            End
               
        End
    Fetch Next From Cur Into
                             @Name           
                            ,@StartDate       
                            ,@EndDate       
                            ,@PatternType   
                            ,@Pattern       
                            ,@Interval       
                            ,@DayOfMonth       
                            ,@WeekNo           
                            ,@DayNo           
                            ,@MonthOfYear   
                            ,@DayOfYear       
                            ,@TimeOccurence   
                            ,@NoOfOccurence
    End
    Close cur
    Deallocate cur

    --// Final Result
    Select dt + @TimeOccurence As Date,Name From @tmp
End

GO

No comments:

Post a Comment