Function to find whether last days of the month is weekend

  • siva 20997 (3/11/2012)


    The last date of the previous month compared to 4/1/2012 is 3/31/2012 which is a Saturday. According to the OP's requirements, it should return the next weekday after that which, of course, should be Monday, 4/2/2012 and not the 4/1/2012 that your function returns.

    On my system 31st March 2012 returns 2nd April 2012

    Uh-huh... Perhaps it's a matter of interpretation on my part, but since 31st March 2012 is in March, the function should actually return 29th February 2012 for that date. It should also return 2nd April 2012 if you use 1st April 2012.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • J Livingston SQL (3/11/2012)


    Jeff Moden (3/10/2012)


    Ok... my turn for a question, folks. Does anyone have a way to do this particular task using a Calendar Table? It doesn't even have to include holidays. I just want to see someone do it because I typically wouldn't use a Calendar Table for such a thing.

    And, no... I'm not bad mouthing anyone's suggestions to use a Calendar Table for this. I'd just like to see it done using one.

    assuming (dangerous :-)) the "calendar" table had columns pre populated with identifieers for weekday and holidays, then couldnt something like this work?

    DECLARE @DateEnq AS DATETIME

    SELECT MIN(calendar_date) AS result

    FROM Calendar

    WHERE (is_weekday = 1)

    AND (is_holiday = 0)

    AND (calendar_date >= (Dateadd(mm, Datediff(mm, 0, @dateenq), 0)) -1)

    -- calendar date greater than or equal to last day of previous month

    Now that's more like it. There are just too many posts that say "use a Calendar" table without actually solving the problem on a given post with Calendar Table code. Well done and thanks a million, Graham. Of course, rising to the occasion isn't something new for you. You're always there "with a good one".

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • for any one interested...here is a quickly mocked up Calendar table and resultant code to answer OP's original question.....by using the calendar table approach.

    Obviously without pre populating the Calendar table with "weekdays" and "holidays" this code cannot work.

    Dependent upon your own needs, this may or may not be useful. The alternative is to process the data "on the fly".

    --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    --PLEASE NOTE THAT THIS WILL DELETE ANY EXG TABLES WITH SAME NAME IN database tempdb....please amend if required

    --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    use [tempdb]

    GO

    --====Conditionally delete tables from [tempdb}

    IF OBJECT_ID('tempdb..Tally', 'U') IS NOT NULL DROP TABLE tempdb..Tally ;

    IF OBJECT_ID('tempdb..Calendar', 'U') IS NOT NULL DROP TABLE tempdb..Calendar ;

    --==== Create a Tally table and a Calendar table

    SELECT TOP 55001 IDENTITY(INT, 0, 1) AS N --- enough for 150 years

    INTO dbo.Tally

    FROM sys.all_columns ac1

    CROSS JOIN sys.all_columns ac2

    CROSS JOIN sys.all_columns ac3

    ALTER TABLE dbo.Tally ADD CONSTRAINT PK_Tally_N PRIMARY KEY CLUSTERED (N) WITH FILLFACTOR = 100

    SET DATEFORMAT DMY

    SET DATEFIRST 1 --- Monday = 1 Sunday = 7

    DECLARE @Date_Start AS DATETIME

    DECLARE @Date_End AS DATETIME

    SET @Date_Start = '01/01/2011'

    SET @Date_End = '31/12/2012'

    CREATE TABLE dbo.Calendar

    (

    calendar_date_ID INT IDENTITY(1, 1) NOT NULL,

    calendar_week_ID INT,

    calendar_date DATETIME PRIMARY KEY CLUSTERED,

    calendar_year SMALLINT,

    calendar_month TINYINT,

    calendar_day TINYINT,

    calendar_quarter TINYINT,

    first_day_in_month DATETIME,

    last_day_in_month DATETIME,

    day_of_week TINYINT,

    week_of_year TINYINT,

    days_in_month TINYINT,

    day_of_year SMALLINT,

    is_weekday INT,

    is_holiday INT default (0),

    day_name VARCHAR (10),

    month_name VARCHAR (10),

    iso_date CHAR (8),

    fiscal_year SMALLINT,

    fiscal_month TINYINT

    );

    INSERT INTO dbo.Calendar

    (calendar_date)

    SELECT t.N + @Date_Start

    FROM dbo.Tally t

    WHERE t.N + @Date_Start <= @Date_End

    UPDATE dbo.Calendar

    SET calendar_week_ID = calendar_date_id / 7 + 1,

    calendar_year = Datepart (YEAR, calendar_date),

    --- fiscal year starts 01 OCT

    fiscal_year = CASE

    WHEN Datepart(M, calendar_date) >= 10 THEN Datepart (YEAR, calendar_date) + 1

    ELSE Datepart (YEAR, calendar_date)

    END,

    calendar_month = Datepart (MONTH, calendar_date),

    fiscal_month = CASE

    WHEN Datepart(M, calendar_date) >= 10 THEN Datepart(M, calendar_date) - 9

    ELSE Datepart(M, calendar_date) + 3

    END,

    calendar_day = Datepart (DAY, calendar_date),

    calendar_quarter = Datepart (QUARTER, calendar_date),

    first_day_in_month = Dateadd(mm, Datediff(mm, 0, calendar_date), 0),

    last_day_in_month = Dateadd(mm, Datediff(mm, 0, calendar_date) + 1, 0) - 1,

    day_of_week = Datepart (WEEKDAY, calendar_date),

    week_of_year = Datepart (WEEK, calendar_date),

    day_of_year = Datepart (DAYOFYEAR, calendar_date),

    is_weekday = CASE

    WHEN Datepart (WEEKDAY, calendar_date) IN (6,7) THEN 0

    ELSE 1

    END ,

    day_name = Datename (WEEKDAY, calendar_date),

    month_name = Datename (MONTH, calendar_date),

    iso_date = CONVERT(CHAR(8), calendar_date, 112),

    days_in_month = Datepart(dd, ( Dateadd(mm, Datediff(mm, 0, calendar_date) + 1, 0) - 1 ))

    select * from calendar

    --===== I am looking for a function to identify whether last day of the previous month is weekday or a weekend.

    -- If it is a weekend then it should return the next weekday.

    -- For example. 31/12/2011 was saturday.

    -- The function should return 02/01/2012 as it was the next working day(Monday).

    -- If it was a weekday then it should return the date.

    DECLARE @DateEnq AS DATETIME

    SET @DateEnq = '05/01/2012'

    SELECT MIN(calendar_date) AS result

    FROM Calendar

    WHERE (is_weekday = 1)

    AND (is_holiday = 0)

    AND (calendar_date >= (Dateadd(mm, Datediff(mm, 0, @dateenq), 0)) -1)

    -- calendar date greater than or equal to last day of previous month

    --- update Calendar table with holidays as required

    UPDATE Calendar

    SET is_holiday = 1

    WHERE (calendar_date = 'YOURHOLIDATES')

    -- rerun and test

    ________________________________________________________________
    you can lead a user to data....but you cannot make them think
    and remember....every day is a school day

  • Ok... I can't hold it back any longer. I've been holding back a bit (a lot, actually). I've used calendar tables on the job since I first learned how to use a Tally Table which was many years ago. In fact, it was an article on a Calendar Table that led me to some code that used a Tally Table (Numbers table, actually).

    I hated that article on Calendar Tables. The code to do simple things like finding the 3rd Wednesday of July (for example) was comparatively complicated, difficult to read, and performed a lot worse than I expected it to even when properly indexed. And trying to solve the problem of being given a date and then finding something like 3 business days later worked well for a single date but absolutely dragged when it came to running large batches of such "delivery" dates.

    That was all way back in SQL Server 2000 long before the joys of ROW_NUMBER(). Right after I discovered how to use Quirky Updates to make up for the missing ROW_NUMBER() function, I applied it to make two very special columns in the Calendar Table to make the previously mentioned problems a whole lot simpler and a whole lot faster. I've put off posting or writing an article about my version of the Calendar Table because it still requires the use of a Quirky Update to build one of the columns (at least until 2012 actually hits the streets) and I frankly didn't want to go through all the negativity from a lot of folks every time I post such a solution.

    One reason why I wanted to see someone else post their solution was to see if anyone else might have been using a (as Celko now calls it) "Julianized Workday Number" to more quickly solve these types of problems. There may be others but Celko is the only other person I've seen use such a column.

    To make a longer story shorter, Quirky Update or not, I guess it's high time for me to write an article on the subject of building and using a Calendar Table with these two very special columns.

    Graham... you're the best. Not only did you provide a solution that used a Calendar Table, but you followed up with the construction of one. Well done. You've shown me that I shouldn't have allowed my trepidation's about posting another Quirky Update solution interfere. With that thought in mind, I'll post the version of the Calendar Table I'm going to use in the article along with some comparisons of methods for the problem in this post tomorrow night.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • I like being contrary so I have to ask, why are you using a calendar table?

    DECLARE @YourDate DATETIME

    SET @YourDate = '2012-01-12'

    SELECT COALESCE(

    CASE WHEN DATEPART(weekday,DATEADD(day,-1,DATEADD(month, DATEDIFF(month, 0, @YourDate), 0))) IN (1,7)

    THEN NULL ELSE DATEADD(day,-1,DATEADD(month, DATEDIFF(month, 0, @YourDate), 0)) END

    ,CASE WHEN DATEPART(weekday,DATEADD(month, DATEDIFF(month, 0, @YourDate), 0)) IN (1,7)

    THEN NULL ELSE DATEADD(month, DATEDIFF(month, 0, @YourDate), 0) END

    ,CASE WHEN DATEPART(weekday,DATEADD(day,1,DATEADD(month, DATEDIFF(month, 0, @YourDate), 0))) IN (1,7)

    THEN NULL ELSE DATEADD(day,1,DATEADD(month, DATEDIFF(month, 0, @YourDate), 0)) END

    )

    I like calendar tables just as much as the next guy, but not for what I understand this question to be.

    Note that the solution depends on DATEPART returning 1 or 7 for the weekend days (i.e., based on SET DATEFIRST).


    My mantra: No loops! No CURSORs! No RBAR! Hoo-uh![/I]

    My thought question: Have you ever been told that your query runs too fast?

    My advice:
    INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
    The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.

    Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
    Since random numbers are too important to be left to chance, let's generate some![/url]
    Learn to understand recursive CTEs by example.[/url]
    [url url=http://www.sqlservercentral.com/articles/St

  • dwain.c (3/12/2012)


    I like being contrary so I have to ask, why are you using a calendar table?

    cos of this q from Jeff

    Jeff Moden (3/10/2012)


    Ok... my turn for a question, folks. Does anyone have a way to do this particular task using a Calendar Table? It doesn't even have to include holidays. I just want to see someone do it because I typically wouldn't use a Calendar Table for such a thing.

    And, no... I'm not bad mouthing anyone's suggestions to use a Calendar Table for this. I'd just like to see it done using one.

    ________________________________________________________________
    you can lead a user to data....but you cannot make them think
    and remember....every day is a school day

  • Indeed, my bad for only skimming through the thread!

    Jeff's was a valid question.


    My mantra: No loops! No CURSORs! No RBAR! Hoo-uh![/I]

    My thought question: Have you ever been told that your query runs too fast?

    My advice:
    INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
    The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.

    Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
    Since random numbers are too important to be left to chance, let's generate some![/url]
    Learn to understand recursive CTEs by example.[/url]
    [url url=http://www.sqlservercentral.com/articles/St

  • oops, didn't see the thread end...

    But still, want to mention that it's not a good idea to use scalar-values user defined SQL function for doing it.

    In-line-sql, may look a bit bulky, will outperform such udf easily.

    Also, cannot see benefits of using of Calendar Table for this particular case...

    _____________________________________________
    "The only true wisdom is in knowing you know nothing"
    "O skol'ko nam otkrytiy chudnyh prevnosit microsofta duh!":-D
    (So many miracle inventions provided by MS to us...)

    How to post your question to get the best and quick help[/url]

  • Eugene

    Would like to know if there is lot of differnce in the perfomance bitween

    User Defined Functions (like what I have posted)

    and system defined functions like DateAdd and DateDiff

    and if So why ?

  • siva 20997 (3/12/2012)


    Eugene

    Would like to know if there is lot of differnce in the perfomance bitween

    User Defined Functions (like what I have posted)

    and system defined functions like DateAdd and DateDiff

    and if So why ?

    There is a huge difference in performance between user-defined-functions and system functions.

    One of the main reasons: System functions are implemented in C++...

    SQL Language is not procedural language, and it's not the best performer when it's used as such. It designed for set-based operations, that is why if you implement the logic "in-line-SQL" (in a select query), it will outperform many other methods.

    At the end, if you really need a scalar-valued function, implement it as CLR function in C#.

    In terms of performance you would have:

    1. in-line-SQL

    2. CLR function (if done properly)

    3. Table-valued user defined SQL function

    4. Scalar-valued user defined SQL function

    I can see some people would argue place 2 and 3, but from my experience, it is so. The key for CLR function implementation - it should be done properly by the skilled c# man 🙂

    _____________________________________________
    "The only true wisdom is in knowing you know nothing"
    "O skol'ko nam otkrytiy chudnyh prevnosit microsofta duh!":-D
    (So many miracle inventions provided by MS to us...)

    How to post your question to get the best and quick help[/url]

  • I do agree with most of your points. But still fail to see couple of things from my understanding of how computers function.

    Wheather the code is inLine or scalar function both are code written by humans. They have to be translated to Assembler/Machine code before execution. It is true of code written in C as well. Becasue the systems functions are Compiled and held at the system level will perfom better. also they are copiled and held most probably in Machine code.

    I am not sure if line code and scalar functions are compiled once and executed many times or it compiled during every cycle( the differnce bitween Compilers and interpreters)

    Other than that my understanding tells me inline and scalar valued functions should perform similarly. The differnce in speed will entirely dependent on how many CPU cycles it takes to execute that code

    I would like to know if I am missing something in undertanding how SQL works ?

  • siva 20997 (3/12/2012)


    I do agree with most of your points. But still fail to see couple of things from my understanding of how computers function.

    Wheather the code is inLine or scalar function both are code written by humans. They have to be translated to Assembler/Machine code before execution. It is true of code written in C as well. Becasue the systems functions are Compiled and held at the system level will perfom better. also they are copiled and held most probably in Machine code.

    I am not sure if line code and scalar functions are compiled once and executed many times or it compiled during every cycle( the differnce bitween Compilers and interpreters)

    Other than that my understanding tells me inline and scalar valued functions should perform similarly. The differnce in speed will entirely dependent on how many CPU cycles it takes to execute that code

    I would like to know if I am missing something in undertanding how SQL works ?

    Very valid points!

    If you really need to understand it from "of how computers function" point of view, which is basically down to "how many CPU cycles it takes to execute that code", the answer is:

    It's takes CPU considerable more number of cycles to execute user-defined scalar functions than system-defined functions in in-line-SQL code. The difference in a number of CPU cycles is so huge, that you are better not use SQL user-defined scalar-valued function when you can do it in in-line-sql. Also, it's big enough difference in CPU cycles compare to CLR (c#) function implementation, to make CLR implementation your second choice.

    You need to analyse the Assembler code for the SQL Server execution to fully and deeply understand the reason behind of such bazaar behaviour :w00t:

    Try this for the starter:

    http://www.crews.org/curriculum/ex/compsci/articles/howcomput.htm

    _____________________________________________
    "The only true wisdom is in knowing you know nothing"
    "O skol'ko nam otkrytiy chudnyh prevnosit microsofta duh!":-D
    (So many miracle inventions provided by MS to us...)

    How to post your question to get the best and quick help[/url]

  • dwain.c (3/12/2012)


    I like being contrary so I have to ask, why are you using a calendar table?

    I'm with you and try to avoid having to reference a table if I don't have to. We actually have a couple of fast, simple, non-Calendar solutions for this. The reason why the Calendar table came up was because it's difficult to properly account for holidays without one. The OP didn't specify such a thing but it seems a logical thing to do.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Eugene Elutin (3/12/2012)


    siva 20997 (3/12/2012)


    Eugene

    Would like to know if there is lot of differnce in the perfomance bitween

    User Defined Functions (like what I have posted)

    and system defined functions like DateAdd and DateDiff

    and if So why ?

    There is a huge difference in performance between user-defined-functions and system functions.

    One of the main reasons: System functions are implemented in C++...

    SQL Language is not procedural language, and it's not the best performer when it's used as such. It designed for set-based operations, that is why if you implement the logic "in-line-SQL" (in a select query), it will outperform many other methods.

    At the end, if you really need a scalar-valued function, implement it as CLR function in C#.

    In terms of performance you would have:

    1. in-line-SQL

    2. CLR function (if done properly)

    3. Table-valued user defined SQL function

    4. Scalar-valued user defined SQL function

    I can see some people would argue place 2 and 3, but from my experience, it is so. The key for CLR function implementation - it should be done properly by the skilled c# man 🙂

    For the most part, I agree but there are some grand exceptions. There are many places where T-SQL code will beat SQLCLR simply because the T-SQL doesn't have to go through an API. An example of such a thing is some simple cases of RegEx. There are also places where Scalar Functions will handily beat Inline code and iTVFs. A good example of such a thing would be a function to replace the first letter of every word with a capitalized version. Oddly enough, not only does the Scalar function win but it also uses a While Loop.

    Rules of thumb are great guides but they should only inspire, not necessarily restrict because for nearly every rule, there's an high performance exception. I've seen lot's of people miss out on some very high performance solutions because their "Rules of thumb" prevented them from even trying alternate ideas.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • J Livingston SQL (3/12/2012)


    dwain.c (3/12/2012)


    I like being contrary so I have to ask, why are you using a calendar table?

    cos of this q from Jeff

    Jeff Moden (3/10/2012)


    Ok... my turn for a question, folks. Does anyone have a way to do this particular task using a Calendar Table? It doesn't even have to include holidays. I just want to see someone do it because I typically wouldn't use a Calendar Table for such a thing.

    And, no... I'm not bad mouthing anyone's suggestions to use a Calendar Table for this. I'd just like to see it done using one.

    I asked the question because someone posted that you could solve this problem with a Calendar Table and pointed to an article that didn't answer the question at hand. :laugh:

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

Viewing 15 posts - 16 through 30 (of 34 total)

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