Amend function to include time values

  • Much better, thank you.

    2. The 2nd scenario is the issue I am having which is not covered by the function.

    If the start date is on a saturday (Sept 6th) at 1200 hrs and end date is the next wednesday (Sept 10th) at 1300 hrs, then in this case the time part till 1200 hrs on saturday will not be included for lag calculation. We need to include the time part from saturday 1200 hrs onwards till 00:00 on sunday because after that its monday and the function is not meant to calculate anything for the weekdays as I mentioned before.

    So in this case the lag calculation will be as follows:

    - Saturday 1200 hrs till Sunday 1200 hrs - 1 lag (24 hours = 1 lag)

    - Sunday 1200 hrs till Sunday 00:00 hrs - 0.5 lag (12 hours = 0.5 lag)

    So the lag in this case is 1.5.

    An easier way of looking at this - well I think so anyway - is as follows:

    - Saturday 1200 hrs till Saturday 2400 hrs (12 hours = 0.5 lag)

    - Sunday 0000 hrs till Sunday 2400 hrs (24 hours = 1.0 lag)

    So the lag in this case is 1.5.

    Any comment?

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • -- Following on from the last post, here's the same query as above with a couple of amendments.

    -- Firstly, I've put the remaining filters into place, the two flag columns.

    -- Secondly, I've added a new column, the weekday of the BUSINESS_DT - so you don't have

    -- to keep looking at your calendar. The date range is saturday to wednesday so it's

    -- your scenario 2.

    DECLARE

    @country VARCHAR(50) = 'United Kingdom',

    @start_dt DATETIME = '2014-07-09 12:29:26',

    @end_dt DATETIME = '2014-07-05 23:30:00.000'

    SELECT

    d.RangeStart,

    d.RangeEnd,

    bc.BUSINESS_DT,

    BUSINESS_DT_day = DATENAME(WEEKDAY,BUSINESS_DT),

    DaysToCount = CASE

    WHEN bc.BUSINESS_DT = CAST(RangeStart AS DATE) THEN 1-CAST(RangeStart AS NUMERIC(9,3))%1

    WHEN bc.BUSINESS_DT = CAST(RangeEnd AS DATE) THEN CAST(RangeEnd AS NUMERIC(9,3))%1

    ELSE 1 END

    FROM (

    SELECT RangeStart = CASE WHEN @start_dt < @end_dt THEN @start_dt ELSE @end_dt END,

    RangeEnd = CASE WHEN @end_dt > @start_dt THEN @end_dt ELSE @start_dt END

    ) d

    INNER JOIN MG_BANK_CALENDAR bc

    ON bc.BUSINESS_DT BETWEEN CAST(RangeStart AS DATE) AND CAST(RangeEnd AS DATE)

    INNER JOIN MG_COUNTRY c

    ON c.COUNTRY_CD = bc.COUNTRY_CD

    WHERE c.COUNTRY_DSC = @country

    AND bc.deleted_flg = 'N'

    AND bc.business_type_flg = 'C'

    RangeStart RangeEnd BUSINESS_DT BUSINESS_DT_day DaysToCount

    2014-07-05 23:30:00.000 2014-07-09 12:29:26.000 2014-07-05 00:00:00.000 Saturday 0.021

    2014-07-05 23:30:00.000 2014-07-09 12:29:26.000 2014-07-06 00:00:00.000 Sunday 1.000

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • ChrisM@Work (9/12/2014)


    Much better, thank you.

    2. The 2nd scenario is the issue I am having which is not covered by the function.

    If the start date is on a saturday (Sept 6th) at 1200 hrs and end date is the next wednesday (Sept 10th) at 1300 hrs, then in this case the time part till 1200 hrs on saturday will not be included for lag calculation. We need to include the time part from saturday 1200 hrs onwards till 00:00 on sunday because after that its monday and the function is not meant to calculate anything for the weekdays as I mentioned before.

    So in this case the lag calculation will be as follows:

    - Saturday 1200 hrs till Sunday 1200 hrs - 1 lag (24 hours = 1 lag)

    - Sunday 1200 hrs till Sunday 00:00 hrs - 0.5 lag (12 hours = 0.5 lag)

    So the lag in this case is 1.5.

    An easier way of looking at this - well I think so anyway - is as follows:

    - Saturday 1200 hrs till Saturday 2400 hrs (12 hours = 0.5 lag)

    - Sunday 0000 hrs till Sunday 2400 hrs (24 hours = 1.0 lag)

    So the lag in this case is 1.5.

    Any comment?

    Yes, you are right, Chris.

  • ChrisM@Work (9/12/2014)


    -- Following on from the last post, here's the same query as above with a couple of amendments.

    -- Firstly, I've put the remaining filters into place, the two flag columns.

    -- Secondly, I've added a new column, the weekday of the BUSINESS_DT - so you don't have

    -- to keep looking at your calendar. The date range is saturday to wednesday so it's

    -- your scenario 2.

    DECLARE

    @country VARCHAR(50) = 'United Kingdom',

    @start_dt DATETIME = '2014-07-09 12:29:26',

    @end_dt DATETIME = '2014-07-05 23:30:00.000'

    SELECT

    d.RangeStart,

    d.RangeEnd,

    bc.BUSINESS_DT,

    BUSINESS_DT_day = DATENAME(WEEKDAY,BUSINESS_DT),

    DaysToCount = CASE

    WHEN bc.BUSINESS_DT = CAST(RangeStart AS DATE) THEN 1-CAST(RangeStart AS NUMERIC(9,3))%1

    WHEN bc.BUSINESS_DT = CAST(RangeEnd AS DATE) THEN CAST(RangeEnd AS NUMERIC(9,3))%1

    ELSE 1 END

    FROM (

    SELECT RangeStart = CASE WHEN @start_dt < @end_dt THEN @start_dt ELSE @end_dt END,

    RangeEnd = CASE WHEN @end_dt > @start_dt THEN @end_dt ELSE @start_dt END

    ) d

    INNER JOIN MG_BANK_CALENDAR bc

    ON bc.BUSINESS_DT BETWEEN CAST(RangeStart AS DATE) AND CAST(RangeEnd AS DATE)

    INNER JOIN MG_COUNTRY c

    ON c.COUNTRY_CD = bc.COUNTRY_CD

    WHERE c.COUNTRY_DSC = @country

    AND bc.deleted_flg = 'N'

    AND bc.business_type_flg = 'C'

    RangeStart RangeEnd BUSINESS_DT BUSINESS_DT_day DaysToCount

    2014-07-05 23:30:00.000 2014-07-09 12:29:26.000 2014-07-05 00:00:00.000 Saturday 0.021

    2014-07-05 23:30:00.000 2014-07-09 12:29:26.000 2014-07-06 00:00:00.000 Sunday 1.000

    I can confirm the result for your query seems correct. It's just that I need to convert this into a function. Thanks.

  • Choose how you wish to tackle DaysToCount, round up or down or whatever and incorporate it into the function.

    CREATE FUNCTION [dbo].[CountFractionalHolidays]

    /*

    Put in some explanatory notes here

    */

    (

    @country VARCHAR(50),

    @start_dt DATETIME,

    @end_dt DATETIME

    )

    RETURNS TABLE AS

    RETURN

    SELECT

    DaysToCount = SUM(CASE

    WHEN bc.BUSINESS_DT = CAST(RangeStart AS DATE) THEN 1-CAST(RangeStart AS NUMERIC(9,3))%1

    WHEN bc.BUSINESS_DT = CAST(RangeEnd AS DATE) THEN CAST(RangeEnd AS NUMERIC(9,3))%1

    ELSE 1 END)

    FROM (

    SELECT RangeStart = CASE WHEN @start_dt < @end_dt THEN @start_dt ELSE @end_dt END,

    RangeEnd = CASE WHEN @end_dt > @start_dt THEN @end_dt ELSE @start_dt END

    ) d

    INNER JOIN dbo.MG_BANK_CALENDAR bc

    ON bc.BUSINESS_DT BETWEEN CAST(RangeStart AS DATE) AND CAST(RangeEnd AS DATE)

    INNER JOIN dbo.MG_COUNTRY c

    ON c.COUNTRY_CD = bc.COUNTRY_CD

    WHERE c.COUNTRY_DSC = @country

    AND bc.deleted_flg = 'N'

    AND bc.business_type_flg = 'C'

    GO

    -- Usage

    SELECT * FROM [dbo].[CountFractionalHolidays]('United Kingdom', '2014-07-09 12:29:26', '2014-07-05 23:30:00.000')

    SELECT m.*, h.DaysToCount

    FROM ( -- this could be any table

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-04 23:30:00.000', EndDate = '2014-07-09 12:29:26' UNION ALL

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-05 23:30:00.000', EndDate = '2014-07-09 12:29:26' UNION ALL

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-05 23:30:00.000', EndDate = '2014-07-06 12:29:26' UNION ALL

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-06 23:30:00.000', EndDate = '2014-07-09 12:29:26'

    ) m

    CROSS APPLY [dbo].[CountFractionalHolidays](m.COUNTRY_DSC, m.StartDate, m.EndDate) h

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • ChrisM@Work (9/12/2014)


    Choose how you wish to tackle DaysToCount, round up or down or whatever and incorporate it into the function.

    CREATE FUNCTION [dbo].[CountFractionalHolidays]

    /*

    Put in some explanatory notes here

    */

    (

    @country VARCHAR(50),

    @start_dt DATETIME,

    @end_dt DATETIME

    )

    RETURNS TABLE AS

    RETURN

    SELECT

    DaysToCount = SUM(CASE

    WHEN bc.BUSINESS_DT = CAST(RangeStart AS DATE) THEN 1-CAST(RangeStart AS NUMERIC(9,3))%1

    WHEN bc.BUSINESS_DT = CAST(RangeEnd AS DATE) THEN CAST(RangeEnd AS NUMERIC(9,3))%1

    ELSE 1 END)

    FROM (

    SELECT RangeStart = CASE WHEN @start_dt < @end_dt THEN @start_dt ELSE @end_dt END,

    RangeEnd = CASE WHEN @end_dt > @start_dt THEN @end_dt ELSE @start_dt END

    ) d

    INNER JOIN dbo.MG_BANK_CALENDAR bc

    ON bc.BUSINESS_DT BETWEEN CAST(RangeStart AS DATE) AND CAST(RangeEnd AS DATE)

    INNER JOIN dbo.MG_COUNTRY c

    ON c.COUNTRY_CD = bc.COUNTRY_CD

    WHERE c.COUNTRY_DSC = @country

    AND bc.deleted_flg = 'N'

    AND bc.business_type_flg = 'C'

    GO

    -- Usage

    SELECT * FROM [dbo].[CountFractionalHolidays]('United Kingdom', '2014-07-09 12:29:26', '2014-07-05 23:30:00.000')

    SELECT m.*, h.DaysToCount

    FROM ( -- this could be any table

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-04 23:30:00.000', EndDate = '2014-07-09 12:29:26' UNION ALL

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-05 23:30:00.000', EndDate = '2014-07-09 12:29:26' UNION ALL

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-05 23:30:00.000', EndDate = '2014-07-06 12:29:26' UNION ALL

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-06 23:30:00.000', EndDate = '2014-07-09 12:29:26'

    ) m

    CROSS APPLY [dbo].[CountFractionalHolidays](m.COUNTRY_DSC, m.StartDate, m.EndDate) h

    Thanks Chris.

    I tried to implement this funtion but as this is a table-valued function, it doesnt fit in the query.

    Could you please suggest something to convert this to a scalar-valued function ?

    Sorry for being so embarrasingly bad in SQL. Thanks.

  • ChrisM@Work (9/12/2014)


    Choose how you wish to tackle DaysToCount, round up or down or whatever and incorporate it into the function.

    CREATE FUNCTION [dbo].[CountFractionalHolidays]

    /*

    Put in some explanatory notes here

    */

    (

    @country VARCHAR(50),

    @start_dt DATETIME,

    @end_dt DATETIME

    )

    RETURNS TABLE AS

    RETURN

    SELECT

    DaysToCount = SUM(CASE

    WHEN bc.BUSINESS_DT = CAST(RangeStart AS DATE) THEN 1-CAST(RangeStart AS NUMERIC(9,3))%1

    WHEN bc.BUSINESS_DT = CAST(RangeEnd AS DATE) THEN CAST(RangeEnd AS NUMERIC(9,3))%1

    ELSE 1 END)

    FROM (

    SELECT RangeStart = CASE WHEN @start_dt < @end_dt THEN @start_dt ELSE @end_dt END,

    RangeEnd = CASE WHEN @end_dt > @start_dt THEN @end_dt ELSE @start_dt END

    ) d

    INNER JOIN dbo.MG_BANK_CALENDAR bc

    ON bc.BUSINESS_DT BETWEEN CAST(RangeStart AS DATE) AND CAST(RangeEnd AS DATE)

    INNER JOIN dbo.MG_COUNTRY c

    ON c.COUNTRY_CD = bc.COUNTRY_CD

    WHERE c.COUNTRY_DSC = @country

    AND bc.deleted_flg = 'N'

    AND bc.business_type_flg = 'C'

    GO

    -- Usage

    SELECT * FROM [dbo].[CountFractionalHolidays]('United Kingdom', '2014-07-09 12:29:26', '2014-07-05 23:30:00.000')

    SELECT m.*, h.DaysToCount

    FROM ( -- this could be any table

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-04 23:30:00.000', EndDate = '2014-07-09 12:29:26' UNION ALL

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-05 23:30:00.000', EndDate = '2014-07-09 12:29:26' UNION ALL

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-05 23:30:00.000', EndDate = '2014-07-06 12:29:26' UNION ALL

    SELECT COUNTRY_DSC = 'United Kingdom', StartDate = '2014-07-06 23:30:00.000', EndDate = '2014-07-09 12:29:26'

    ) m

    CROSS APPLY [dbo].[CountFractionalHolidays](m.COUNTRY_DSC, m.StartDate, m.EndDate) h

    Thanks a lot , Chris !! Did some manipulation to your suggested code and it worked perfectly !

Viewing 7 posts - 16 through 21 (of 21 total)

You must be logged in to reply to this topic. Login to reply