Calculate total and elapsed number of working days in the month for a given date









up vote
0
down vote

favorite
1












I am stuck with a SQL query.



I am trying to calculate two different things in a same query:



  1. Number of business days in a month (this will exclude weekends).

  2. How many days working days have been passed in a month.

Let's say for November (as on 11/9/2018)



no.of business days no. of business days passed
22 7


I tried like this :



WITH cteAllDates AS 
(
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME

SET @StartDate = '10/01/2018'
SET @EndDate = '10/31/2018'

SELECT
(DATEDIFF(dd, @StartDate, @EndDate) + 1)
- (DATEDIFF(wk, @StartDate, @EndDate) * 2)
- (CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) AS x
) AS y
SELECT x
FROM cteAllDates


I would like to create a virtual table so that I can use these fields in my complete query. And if its possible I can do this with GETDATE() and not to declare dates every time.










share|improve this question























  • should no.of business days be 22 in NOV?
    – D-Shih
    Nov 10 at 0:27






  • 1




    I would recommend creating a calendar table with lots of precalculated data, e.g. number of business days in a month. In your case you can add a *business day number" starting with the first day of your calendar which increases only for business days (it's easy to exclude public holidays, too). Now the number of business days between two dates is calculated as a difference using two joins to the calendar...
    – dnoeth
    Nov 10 at 11:35















up vote
0
down vote

favorite
1












I am stuck with a SQL query.



I am trying to calculate two different things in a same query:



  1. Number of business days in a month (this will exclude weekends).

  2. How many days working days have been passed in a month.

Let's say for November (as on 11/9/2018)



no.of business days no. of business days passed
22 7


I tried like this :



WITH cteAllDates AS 
(
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME

SET @StartDate = '10/01/2018'
SET @EndDate = '10/31/2018'

SELECT
(DATEDIFF(dd, @StartDate, @EndDate) + 1)
- (DATEDIFF(wk, @StartDate, @EndDate) * 2)
- (CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) AS x
) AS y
SELECT x
FROM cteAllDates


I would like to create a virtual table so that I can use these fields in my complete query. And if its possible I can do this with GETDATE() and not to declare dates every time.










share|improve this question























  • should no.of business days be 22 in NOV?
    – D-Shih
    Nov 10 at 0:27






  • 1




    I would recommend creating a calendar table with lots of precalculated data, e.g. number of business days in a month. In your case you can add a *business day number" starting with the first day of your calendar which increases only for business days (it's easy to exclude public holidays, too). Now the number of business days between two dates is calculated as a difference using two joins to the calendar...
    – dnoeth
    Nov 10 at 11:35













up vote
0
down vote

favorite
1









up vote
0
down vote

favorite
1






1





I am stuck with a SQL query.



I am trying to calculate two different things in a same query:



  1. Number of business days in a month (this will exclude weekends).

  2. How many days working days have been passed in a month.

Let's say for November (as on 11/9/2018)



no.of business days no. of business days passed
22 7


I tried like this :



WITH cteAllDates AS 
(
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME

SET @StartDate = '10/01/2018'
SET @EndDate = '10/31/2018'

SELECT
(DATEDIFF(dd, @StartDate, @EndDate) + 1)
- (DATEDIFF(wk, @StartDate, @EndDate) * 2)
- (CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) AS x
) AS y
SELECT x
FROM cteAllDates


I would like to create a virtual table so that I can use these fields in my complete query. And if its possible I can do this with GETDATE() and not to declare dates every time.










share|improve this question















I am stuck with a SQL query.



I am trying to calculate two different things in a same query:



  1. Number of business days in a month (this will exclude weekends).

  2. How many days working days have been passed in a month.

Let's say for November (as on 11/9/2018)



no.of business days no. of business days passed
22 7


I tried like this :



WITH cteAllDates AS 
(
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME

SET @StartDate = '10/01/2018'
SET @EndDate = '10/31/2018'

SELECT
(DATEDIFF(dd, @StartDate, @EndDate) + 1)
- (DATEDIFF(wk, @StartDate, @EndDate) * 2)
- (CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) AS x
) AS y
SELECT x
FROM cteAllDates


I would like to create a virtual table so that I can use these fields in my complete query. And if its possible I can do this with GETDATE() and not to declare dates every time.







sql sql-server sql-server-2008 datetime






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 14 at 6:57









Salman A

172k65329415




172k65329415










asked Nov 9 at 23:51









jsingh

696




696











  • should no.of business days be 22 in NOV?
    – D-Shih
    Nov 10 at 0:27






  • 1




    I would recommend creating a calendar table with lots of precalculated data, e.g. number of business days in a month. In your case you can add a *business day number" starting with the first day of your calendar which increases only for business days (it's easy to exclude public holidays, too). Now the number of business days between two dates is calculated as a difference using two joins to the calendar...
    – dnoeth
    Nov 10 at 11:35

















  • should no.of business days be 22 in NOV?
    – D-Shih
    Nov 10 at 0:27






  • 1




    I would recommend creating a calendar table with lots of precalculated data, e.g. number of business days in a month. In your case you can add a *business day number" starting with the first day of your calendar which increases only for business days (it's easy to exclude public holidays, too). Now the number of business days between two dates is calculated as a difference using two joins to the calendar...
    – dnoeth
    Nov 10 at 11:35
















should no.of business days be 22 in NOV?
– D-Shih
Nov 10 at 0:27




should no.of business days be 22 in NOV?
– D-Shih
Nov 10 at 0:27




1




1




I would recommend creating a calendar table with lots of precalculated data, e.g. number of business days in a month. In your case you can add a *business day number" starting with the first day of your calendar which increases only for business days (it's easy to exclude public holidays, too). Now the number of business days between two dates is calculated as a difference using two joins to the calendar...
– dnoeth
Nov 10 at 11:35





I would recommend creating a calendar table with lots of precalculated data, e.g. number of business days in a month. In your case you can add a *business day number" starting with the first day of your calendar which increases only for business days (it's easy to exclude public holidays, too). Now the number of business days between two dates is calculated as a difference using two joins to the calendar...
– dnoeth
Nov 10 at 11:35













3 Answers
3






active

oldest

votes

















up vote
1
down vote



accepted










Since you want to do it in a CTE, and based on the earlier answer you found on SO, here is a version that does it all for the current month without needing to define start and end dates:



EDIT: To create a holiday table



First, create a holiday table. Don't do this every time, make it a persistent table, and keep it filled up with all holidays you need - easter, xmas etc.



create table holidays(holiday date)
insert holidays values ('2018-09-23'),('2018-09-24')


Now the query, including the check for number of holidays between the dates



;with dates as(
select dateadd(d,-day(getdate())+1,convert(date,getdate())) as startofmonth,
dateadd(d,-1,dateadd(m,1,dateadd(d,-day(getdate())+1,convert(date,getdate())))) as endofmonth,
convert(date,getdate()) as today
)
,holidaycount as (
select count(*) as holidaysinmonth,
sum(case when holiday<=today then 1 else 0 end) as holidaystodate
from dates
join holidays on holiday between startofmonth and endofmonth
)
,daycounts as(
select dates.*,

(DATEDIFF(dd, startofmonth, endofmonth) + 1)
-(DATEDIFF(wk, startofmonth, endofmonth) * 2)
-(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, endofmonth) = 'Saturday' THEN 1 ELSE 0 END)
-isnull(holidaysinmonth,0) as wkdaysinmonth,

(DATEDIFF(dd, startofmonth, today) + 1)
-(DATEDIFF(wk, startofmonth, today) * 2)
-(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, today) = 'Saturday' THEN 1 ELSE 0 END)
-isnull(holidaystodate,0) as wkdaystodate

from dates
cross join holidaycount
)

select * from daycounts


EDIT: If you cant create a temp table, add this as an additional CTE before the holidaycount one like so:



,holidays as (
select holiday from (values ('2018-11-23'),('2018-11-24')) t(holiday)
)
,holidaycount as (





share|improve this answer






















  • @TomC..Thanku for replying me out..this is really working out good. But I would like to know if in November I would like to exclude 23 and 24 november from this ( i mean those are holidays). how i will add that to this query?
    – jsingh
    Nov 14 at 23:42










  • Once you start adding in holidays then you go towards the other suggestions in the comments and other answers - where you create a separate calendar table that includes every date, and flags for working days, holidays etc. Then it becomes a simple case of counting the relevant days.
    – TomC
    Nov 15 at 0:53










  • @TomC..can u please show me how to do it?..In november i want to exclude 22nd november..How i will create a calender table?
    – jsingh
    Nov 16 at 0:34











  • I have updated to use a simple holiday table that just contains the holiday dates. Make sure you only enter week day holidays.
    – TomC
    Nov 16 at 7:04










  • @TomC..Hi I am getting an error There is already an object named 'holidays' in the database.
    – jsingh
    Nov 16 at 17:52

















up vote
0
down vote













You can try to use cte recursive make a calendar table, then use condition aggregate function to get your result.



DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = DATEADD(DAY, 1, EOMONTH(GETDATE(), -1));
SET @EndDate = DATEADD(DAY, 1, EOMONTH(GETDATE()));

;WITH CTE AS (
select @StartDate startdt,@EndDate enddt
UNION ALL
SELECT DATEADD (day ,1 , startdt) , @EndDate
FROM CTE
WHERE DATEADD (day,1,startdt) <= @EndDate
)


select SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') THEN 1 END) 'no.of business days',
SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') AND GETDATE() >= startdt THEN 1 END) 'no. of business days passed'
FROM CTE


sqlfiddle



Result



no.of business days no. of business days passed
22 7





share|improve this answer






















  • @D-Shih..This query is not returning me any results.
    – jsingh
    Nov 10 at 0:35










  • @jsingh sqlfiddle work good... maybe you can check the @StartDate and @EndDate var
    – D-Shih
    Nov 10 at 0:37










  • @jsingh You can try my edit answer
    – D-Shih
    Nov 10 at 1:18

















up vote
0
down vote













You can do this without recursive CTE as long as you want data for a single month.



  • There are 20 working days in first 28 days on month. Just check 29, 30 and 31

  • There are 5 working days in first 7 days, 10 in 14 and so on. Just check 6 days.

DECLARE @dt AS DATE = '2018-11-09';
WITH vars1 AS (
SELECT
d1 = DATEADD(dd, 1, EOMONTH(@dt, -1)),
dn = EOMONTH(@dt),
wks = DAY(@dt) / 7
), vars AS (
SELECT
d1, -- first day of month
dn, -- last day of month
wks, -- number of 7-day intervals elapsed
d29 = DATEADD(dd, 28, d1), -- 29th day of month
d30 = DATEADD(dd, 29, d1),
d31 = DATEADD(dd, 30, d1),
dp1 = DATEADD(dd, wks * 7 + 0, d1), -- wks * 7 gives you 0, 7, 14, 21 or 28
dp2 = DATEADD(dd, wks * 7 + 1, d1), -- wks * 7 + 0 ... 5 are the dates to check
dp3 = DATEADD(dd, wks * 7 + 2, d1),
dp4 = DATEADD(dd, wks * 7 + 3, d1),
dp5 = DATEADD(dd, wks * 7 + 4, d1),
dp6 = DATEADD(dd, wks * 7 + 5, d1)
FROM vars1
)
SELECT
[no. of business days] = 20 +
IIF(d29 <= dn AND DATENAME(dw, d29) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(d30 <= dn AND DATENAME(dw, d30) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(d31 <= dn AND DATENAME(dw, d31) NOT IN ('Saturday', 'Sunday'), 1, 0),
[no. of business days passed] = wks * 5 +
IIF(dp1 <= @dt AND DATENAME(dw, dp1) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(dp2 <= @dt AND DATENAME(dw, dp2) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(dp3 <= @dt AND DATENAME(dw, dp3) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(dp4 <= @dt AND DATENAME(dw, dp4) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(dp5 <= @dt AND DATENAME(dw, dp5) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(dp6 <= @dt AND DATENAME(dw, dp6) NOT IN ('Saturday', 'Sunday'), 1, 0)
FROM vars


DB Fiddle






share|improve this answer






















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53234712%2fcalculate-total-and-elapsed-number-of-working-days-in-the-month-for-a-given-date%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote



    accepted










    Since you want to do it in a CTE, and based on the earlier answer you found on SO, here is a version that does it all for the current month without needing to define start and end dates:



    EDIT: To create a holiday table



    First, create a holiday table. Don't do this every time, make it a persistent table, and keep it filled up with all holidays you need - easter, xmas etc.



    create table holidays(holiday date)
    insert holidays values ('2018-09-23'),('2018-09-24')


    Now the query, including the check for number of holidays between the dates



    ;with dates as(
    select dateadd(d,-day(getdate())+1,convert(date,getdate())) as startofmonth,
    dateadd(d,-1,dateadd(m,1,dateadd(d,-day(getdate())+1,convert(date,getdate())))) as endofmonth,
    convert(date,getdate()) as today
    )
    ,holidaycount as (
    select count(*) as holidaysinmonth,
    sum(case when holiday<=today then 1 else 0 end) as holidaystodate
    from dates
    join holidays on holiday between startofmonth and endofmonth
    )
    ,daycounts as(
    select dates.*,

    (DATEDIFF(dd, startofmonth, endofmonth) + 1)
    -(DATEDIFF(wk, startofmonth, endofmonth) * 2)
    -(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
    -(CASE WHEN DATENAME(dw, endofmonth) = 'Saturday' THEN 1 ELSE 0 END)
    -isnull(holidaysinmonth,0) as wkdaysinmonth,

    (DATEDIFF(dd, startofmonth, today) + 1)
    -(DATEDIFF(wk, startofmonth, today) * 2)
    -(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
    -(CASE WHEN DATENAME(dw, today) = 'Saturday' THEN 1 ELSE 0 END)
    -isnull(holidaystodate,0) as wkdaystodate

    from dates
    cross join holidaycount
    )

    select * from daycounts


    EDIT: If you cant create a temp table, add this as an additional CTE before the holidaycount one like so:



    ,holidays as (
    select holiday from (values ('2018-11-23'),('2018-11-24')) t(holiday)
    )
    ,holidaycount as (





    share|improve this answer






















    • @TomC..Thanku for replying me out..this is really working out good. But I would like to know if in November I would like to exclude 23 and 24 november from this ( i mean those are holidays). how i will add that to this query?
      – jsingh
      Nov 14 at 23:42










    • Once you start adding in holidays then you go towards the other suggestions in the comments and other answers - where you create a separate calendar table that includes every date, and flags for working days, holidays etc. Then it becomes a simple case of counting the relevant days.
      – TomC
      Nov 15 at 0:53










    • @TomC..can u please show me how to do it?..In november i want to exclude 22nd november..How i will create a calender table?
      – jsingh
      Nov 16 at 0:34











    • I have updated to use a simple holiday table that just contains the holiday dates. Make sure you only enter week day holidays.
      – TomC
      Nov 16 at 7:04










    • @TomC..Hi I am getting an error There is already an object named 'holidays' in the database.
      – jsingh
      Nov 16 at 17:52














    up vote
    1
    down vote



    accepted










    Since you want to do it in a CTE, and based on the earlier answer you found on SO, here is a version that does it all for the current month without needing to define start and end dates:



    EDIT: To create a holiday table



    First, create a holiday table. Don't do this every time, make it a persistent table, and keep it filled up with all holidays you need - easter, xmas etc.



    create table holidays(holiday date)
    insert holidays values ('2018-09-23'),('2018-09-24')


    Now the query, including the check for number of holidays between the dates



    ;with dates as(
    select dateadd(d,-day(getdate())+1,convert(date,getdate())) as startofmonth,
    dateadd(d,-1,dateadd(m,1,dateadd(d,-day(getdate())+1,convert(date,getdate())))) as endofmonth,
    convert(date,getdate()) as today
    )
    ,holidaycount as (
    select count(*) as holidaysinmonth,
    sum(case when holiday<=today then 1 else 0 end) as holidaystodate
    from dates
    join holidays on holiday between startofmonth and endofmonth
    )
    ,daycounts as(
    select dates.*,

    (DATEDIFF(dd, startofmonth, endofmonth) + 1)
    -(DATEDIFF(wk, startofmonth, endofmonth) * 2)
    -(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
    -(CASE WHEN DATENAME(dw, endofmonth) = 'Saturday' THEN 1 ELSE 0 END)
    -isnull(holidaysinmonth,0) as wkdaysinmonth,

    (DATEDIFF(dd, startofmonth, today) + 1)
    -(DATEDIFF(wk, startofmonth, today) * 2)
    -(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
    -(CASE WHEN DATENAME(dw, today) = 'Saturday' THEN 1 ELSE 0 END)
    -isnull(holidaystodate,0) as wkdaystodate

    from dates
    cross join holidaycount
    )

    select * from daycounts


    EDIT: If you cant create a temp table, add this as an additional CTE before the holidaycount one like so:



    ,holidays as (
    select holiday from (values ('2018-11-23'),('2018-11-24')) t(holiday)
    )
    ,holidaycount as (





    share|improve this answer






















    • @TomC..Thanku for replying me out..this is really working out good. But I would like to know if in November I would like to exclude 23 and 24 november from this ( i mean those are holidays). how i will add that to this query?
      – jsingh
      Nov 14 at 23:42










    • Once you start adding in holidays then you go towards the other suggestions in the comments and other answers - where you create a separate calendar table that includes every date, and flags for working days, holidays etc. Then it becomes a simple case of counting the relevant days.
      – TomC
      Nov 15 at 0:53










    • @TomC..can u please show me how to do it?..In november i want to exclude 22nd november..How i will create a calender table?
      – jsingh
      Nov 16 at 0:34











    • I have updated to use a simple holiday table that just contains the holiday dates. Make sure you only enter week day holidays.
      – TomC
      Nov 16 at 7:04










    • @TomC..Hi I am getting an error There is already an object named 'holidays' in the database.
      – jsingh
      Nov 16 at 17:52












    up vote
    1
    down vote



    accepted







    up vote
    1
    down vote



    accepted






    Since you want to do it in a CTE, and based on the earlier answer you found on SO, here is a version that does it all for the current month without needing to define start and end dates:



    EDIT: To create a holiday table



    First, create a holiday table. Don't do this every time, make it a persistent table, and keep it filled up with all holidays you need - easter, xmas etc.



    create table holidays(holiday date)
    insert holidays values ('2018-09-23'),('2018-09-24')


    Now the query, including the check for number of holidays between the dates



    ;with dates as(
    select dateadd(d,-day(getdate())+1,convert(date,getdate())) as startofmonth,
    dateadd(d,-1,dateadd(m,1,dateadd(d,-day(getdate())+1,convert(date,getdate())))) as endofmonth,
    convert(date,getdate()) as today
    )
    ,holidaycount as (
    select count(*) as holidaysinmonth,
    sum(case when holiday<=today then 1 else 0 end) as holidaystodate
    from dates
    join holidays on holiday between startofmonth and endofmonth
    )
    ,daycounts as(
    select dates.*,

    (DATEDIFF(dd, startofmonth, endofmonth) + 1)
    -(DATEDIFF(wk, startofmonth, endofmonth) * 2)
    -(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
    -(CASE WHEN DATENAME(dw, endofmonth) = 'Saturday' THEN 1 ELSE 0 END)
    -isnull(holidaysinmonth,0) as wkdaysinmonth,

    (DATEDIFF(dd, startofmonth, today) + 1)
    -(DATEDIFF(wk, startofmonth, today) * 2)
    -(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
    -(CASE WHEN DATENAME(dw, today) = 'Saturday' THEN 1 ELSE 0 END)
    -isnull(holidaystodate,0) as wkdaystodate

    from dates
    cross join holidaycount
    )

    select * from daycounts


    EDIT: If you cant create a temp table, add this as an additional CTE before the holidaycount one like so:



    ,holidays as (
    select holiday from (values ('2018-11-23'),('2018-11-24')) t(holiday)
    )
    ,holidaycount as (





    share|improve this answer














    Since you want to do it in a CTE, and based on the earlier answer you found on SO, here is a version that does it all for the current month without needing to define start and end dates:



    EDIT: To create a holiday table



    First, create a holiday table. Don't do this every time, make it a persistent table, and keep it filled up with all holidays you need - easter, xmas etc.



    create table holidays(holiday date)
    insert holidays values ('2018-09-23'),('2018-09-24')


    Now the query, including the check for number of holidays between the dates



    ;with dates as(
    select dateadd(d,-day(getdate())+1,convert(date,getdate())) as startofmonth,
    dateadd(d,-1,dateadd(m,1,dateadd(d,-day(getdate())+1,convert(date,getdate())))) as endofmonth,
    convert(date,getdate()) as today
    )
    ,holidaycount as (
    select count(*) as holidaysinmonth,
    sum(case when holiday<=today then 1 else 0 end) as holidaystodate
    from dates
    join holidays on holiday between startofmonth and endofmonth
    )
    ,daycounts as(
    select dates.*,

    (DATEDIFF(dd, startofmonth, endofmonth) + 1)
    -(DATEDIFF(wk, startofmonth, endofmonth) * 2)
    -(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
    -(CASE WHEN DATENAME(dw, endofmonth) = 'Saturday' THEN 1 ELSE 0 END)
    -isnull(holidaysinmonth,0) as wkdaysinmonth,

    (DATEDIFF(dd, startofmonth, today) + 1)
    -(DATEDIFF(wk, startofmonth, today) * 2)
    -(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
    -(CASE WHEN DATENAME(dw, today) = 'Saturday' THEN 1 ELSE 0 END)
    -isnull(holidaystodate,0) as wkdaystodate

    from dates
    cross join holidaycount
    )

    select * from daycounts


    EDIT: If you cant create a temp table, add this as an additional CTE before the holidaycount one like so:



    ,holidays as (
    select holiday from (values ('2018-11-23'),('2018-11-24')) t(holiday)
    )
    ,holidaycount as (






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 19 at 23:01

























    answered Nov 10 at 0:35









    TomC

    1,366139




    1,366139











    • @TomC..Thanku for replying me out..this is really working out good. But I would like to know if in November I would like to exclude 23 and 24 november from this ( i mean those are holidays). how i will add that to this query?
      – jsingh
      Nov 14 at 23:42










    • Once you start adding in holidays then you go towards the other suggestions in the comments and other answers - where you create a separate calendar table that includes every date, and flags for working days, holidays etc. Then it becomes a simple case of counting the relevant days.
      – TomC
      Nov 15 at 0:53










    • @TomC..can u please show me how to do it?..In november i want to exclude 22nd november..How i will create a calender table?
      – jsingh
      Nov 16 at 0:34











    • I have updated to use a simple holiday table that just contains the holiday dates. Make sure you only enter week day holidays.
      – TomC
      Nov 16 at 7:04










    • @TomC..Hi I am getting an error There is already an object named 'holidays' in the database.
      – jsingh
      Nov 16 at 17:52
















    • @TomC..Thanku for replying me out..this is really working out good. But I would like to know if in November I would like to exclude 23 and 24 november from this ( i mean those are holidays). how i will add that to this query?
      – jsingh
      Nov 14 at 23:42










    • Once you start adding in holidays then you go towards the other suggestions in the comments and other answers - where you create a separate calendar table that includes every date, and flags for working days, holidays etc. Then it becomes a simple case of counting the relevant days.
      – TomC
      Nov 15 at 0:53










    • @TomC..can u please show me how to do it?..In november i want to exclude 22nd november..How i will create a calender table?
      – jsingh
      Nov 16 at 0:34











    • I have updated to use a simple holiday table that just contains the holiday dates. Make sure you only enter week day holidays.
      – TomC
      Nov 16 at 7:04










    • @TomC..Hi I am getting an error There is already an object named 'holidays' in the database.
      – jsingh
      Nov 16 at 17:52















    @TomC..Thanku for replying me out..this is really working out good. But I would like to know if in November I would like to exclude 23 and 24 november from this ( i mean those are holidays). how i will add that to this query?
    – jsingh
    Nov 14 at 23:42




    @TomC..Thanku for replying me out..this is really working out good. But I would like to know if in November I would like to exclude 23 and 24 november from this ( i mean those are holidays). how i will add that to this query?
    – jsingh
    Nov 14 at 23:42












    Once you start adding in holidays then you go towards the other suggestions in the comments and other answers - where you create a separate calendar table that includes every date, and flags for working days, holidays etc. Then it becomes a simple case of counting the relevant days.
    – TomC
    Nov 15 at 0:53




    Once you start adding in holidays then you go towards the other suggestions in the comments and other answers - where you create a separate calendar table that includes every date, and flags for working days, holidays etc. Then it becomes a simple case of counting the relevant days.
    – TomC
    Nov 15 at 0:53












    @TomC..can u please show me how to do it?..In november i want to exclude 22nd november..How i will create a calender table?
    – jsingh
    Nov 16 at 0:34





    @TomC..can u please show me how to do it?..In november i want to exclude 22nd november..How i will create a calender table?
    – jsingh
    Nov 16 at 0:34













    I have updated to use a simple holiday table that just contains the holiday dates. Make sure you only enter week day holidays.
    – TomC
    Nov 16 at 7:04




    I have updated to use a simple holiday table that just contains the holiday dates. Make sure you only enter week day holidays.
    – TomC
    Nov 16 at 7:04












    @TomC..Hi I am getting an error There is already an object named 'holidays' in the database.
    – jsingh
    Nov 16 at 17:52




    @TomC..Hi I am getting an error There is already an object named 'holidays' in the database.
    – jsingh
    Nov 16 at 17:52












    up vote
    0
    down vote













    You can try to use cte recursive make a calendar table, then use condition aggregate function to get your result.



    DECLARE @StartDate DATETIME
    DECLARE @EndDate DATETIME
    SET @StartDate = DATEADD(DAY, 1, EOMONTH(GETDATE(), -1));
    SET @EndDate = DATEADD(DAY, 1, EOMONTH(GETDATE()));

    ;WITH CTE AS (
    select @StartDate startdt,@EndDate enddt
    UNION ALL
    SELECT DATEADD (day ,1 , startdt) , @EndDate
    FROM CTE
    WHERE DATEADD (day,1,startdt) <= @EndDate
    )


    select SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') THEN 1 END) 'no.of business days',
    SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') AND GETDATE() >= startdt THEN 1 END) 'no. of business days passed'
    FROM CTE


    sqlfiddle



    Result



    no.of business days no. of business days passed
    22 7





    share|improve this answer






















    • @D-Shih..This query is not returning me any results.
      – jsingh
      Nov 10 at 0:35










    • @jsingh sqlfiddle work good... maybe you can check the @StartDate and @EndDate var
      – D-Shih
      Nov 10 at 0:37










    • @jsingh You can try my edit answer
      – D-Shih
      Nov 10 at 1:18














    up vote
    0
    down vote













    You can try to use cte recursive make a calendar table, then use condition aggregate function to get your result.



    DECLARE @StartDate DATETIME
    DECLARE @EndDate DATETIME
    SET @StartDate = DATEADD(DAY, 1, EOMONTH(GETDATE(), -1));
    SET @EndDate = DATEADD(DAY, 1, EOMONTH(GETDATE()));

    ;WITH CTE AS (
    select @StartDate startdt,@EndDate enddt
    UNION ALL
    SELECT DATEADD (day ,1 , startdt) , @EndDate
    FROM CTE
    WHERE DATEADD (day,1,startdt) <= @EndDate
    )


    select SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') THEN 1 END) 'no.of business days',
    SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') AND GETDATE() >= startdt THEN 1 END) 'no. of business days passed'
    FROM CTE


    sqlfiddle



    Result



    no.of business days no. of business days passed
    22 7





    share|improve this answer






















    • @D-Shih..This query is not returning me any results.
      – jsingh
      Nov 10 at 0:35










    • @jsingh sqlfiddle work good... maybe you can check the @StartDate and @EndDate var
      – D-Shih
      Nov 10 at 0:37










    • @jsingh You can try my edit answer
      – D-Shih
      Nov 10 at 1:18












    up vote
    0
    down vote










    up vote
    0
    down vote









    You can try to use cte recursive make a calendar table, then use condition aggregate function to get your result.



    DECLARE @StartDate DATETIME
    DECLARE @EndDate DATETIME
    SET @StartDate = DATEADD(DAY, 1, EOMONTH(GETDATE(), -1));
    SET @EndDate = DATEADD(DAY, 1, EOMONTH(GETDATE()));

    ;WITH CTE AS (
    select @StartDate startdt,@EndDate enddt
    UNION ALL
    SELECT DATEADD (day ,1 , startdt) , @EndDate
    FROM CTE
    WHERE DATEADD (day,1,startdt) <= @EndDate
    )


    select SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') THEN 1 END) 'no.of business days',
    SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') AND GETDATE() >= startdt THEN 1 END) 'no. of business days passed'
    FROM CTE


    sqlfiddle



    Result



    no.of business days no. of business days passed
    22 7





    share|improve this answer














    You can try to use cte recursive make a calendar table, then use condition aggregate function to get your result.



    DECLARE @StartDate DATETIME
    DECLARE @EndDate DATETIME
    SET @StartDate = DATEADD(DAY, 1, EOMONTH(GETDATE(), -1));
    SET @EndDate = DATEADD(DAY, 1, EOMONTH(GETDATE()));

    ;WITH CTE AS (
    select @StartDate startdt,@EndDate enddt
    UNION ALL
    SELECT DATEADD (day ,1 , startdt) , @EndDate
    FROM CTE
    WHERE DATEADD (day,1,startdt) <= @EndDate
    )


    select SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') THEN 1 END) 'no.of business days',
    SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') AND GETDATE() >= startdt THEN 1 END) 'no. of business days passed'
    FROM CTE


    sqlfiddle



    Result



    no.of business days no. of business days passed
    22 7






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 10 at 1:00

























    answered Nov 10 at 0:26









    D-Shih

    24.3k61431




    24.3k61431











    • @D-Shih..This query is not returning me any results.
      – jsingh
      Nov 10 at 0:35










    • @jsingh sqlfiddle work good... maybe you can check the @StartDate and @EndDate var
      – D-Shih
      Nov 10 at 0:37










    • @jsingh You can try my edit answer
      – D-Shih
      Nov 10 at 1:18
















    • @D-Shih..This query is not returning me any results.
      – jsingh
      Nov 10 at 0:35










    • @jsingh sqlfiddle work good... maybe you can check the @StartDate and @EndDate var
      – D-Shih
      Nov 10 at 0:37










    • @jsingh You can try my edit answer
      – D-Shih
      Nov 10 at 1:18















    @D-Shih..This query is not returning me any results.
    – jsingh
    Nov 10 at 0:35




    @D-Shih..This query is not returning me any results.
    – jsingh
    Nov 10 at 0:35












    @jsingh sqlfiddle work good... maybe you can check the @StartDate and @EndDate var
    – D-Shih
    Nov 10 at 0:37




    @jsingh sqlfiddle work good... maybe you can check the @StartDate and @EndDate var
    – D-Shih
    Nov 10 at 0:37












    @jsingh You can try my edit answer
    – D-Shih
    Nov 10 at 1:18




    @jsingh You can try my edit answer
    – D-Shih
    Nov 10 at 1:18










    up vote
    0
    down vote













    You can do this without recursive CTE as long as you want data for a single month.



    • There are 20 working days in first 28 days on month. Just check 29, 30 and 31

    • There are 5 working days in first 7 days, 10 in 14 and so on. Just check 6 days.

    DECLARE @dt AS DATE = '2018-11-09';
    WITH vars1 AS (
    SELECT
    d1 = DATEADD(dd, 1, EOMONTH(@dt, -1)),
    dn = EOMONTH(@dt),
    wks = DAY(@dt) / 7
    ), vars AS (
    SELECT
    d1, -- first day of month
    dn, -- last day of month
    wks, -- number of 7-day intervals elapsed
    d29 = DATEADD(dd, 28, d1), -- 29th day of month
    d30 = DATEADD(dd, 29, d1),
    d31 = DATEADD(dd, 30, d1),
    dp1 = DATEADD(dd, wks * 7 + 0, d1), -- wks * 7 gives you 0, 7, 14, 21 or 28
    dp2 = DATEADD(dd, wks * 7 + 1, d1), -- wks * 7 + 0 ... 5 are the dates to check
    dp3 = DATEADD(dd, wks * 7 + 2, d1),
    dp4 = DATEADD(dd, wks * 7 + 3, d1),
    dp5 = DATEADD(dd, wks * 7 + 4, d1),
    dp6 = DATEADD(dd, wks * 7 + 5, d1)
    FROM vars1
    )
    SELECT
    [no. of business days] = 20 +
    IIF(d29 <= dn AND DATENAME(dw, d29) NOT IN ('Saturday', 'Sunday'), 1, 0) +
    IIF(d30 <= dn AND DATENAME(dw, d30) NOT IN ('Saturday', 'Sunday'), 1, 0) +
    IIF(d31 <= dn AND DATENAME(dw, d31) NOT IN ('Saturday', 'Sunday'), 1, 0),
    [no. of business days passed] = wks * 5 +
    IIF(dp1 <= @dt AND DATENAME(dw, dp1) NOT IN ('Saturday', 'Sunday'), 1, 0) +
    IIF(dp2 <= @dt AND DATENAME(dw, dp2) NOT IN ('Saturday', 'Sunday'), 1, 0) +
    IIF(dp3 <= @dt AND DATENAME(dw, dp3) NOT IN ('Saturday', 'Sunday'), 1, 0) +
    IIF(dp4 <= @dt AND DATENAME(dw, dp4) NOT IN ('Saturday', 'Sunday'), 1, 0) +
    IIF(dp5 <= @dt AND DATENAME(dw, dp5) NOT IN ('Saturday', 'Sunday'), 1, 0) +
    IIF(dp6 <= @dt AND DATENAME(dw, dp6) NOT IN ('Saturday', 'Sunday'), 1, 0)
    FROM vars


    DB Fiddle






    share|improve this answer


























      up vote
      0
      down vote













      You can do this without recursive CTE as long as you want data for a single month.



      • There are 20 working days in first 28 days on month. Just check 29, 30 and 31

      • There are 5 working days in first 7 days, 10 in 14 and so on. Just check 6 days.

      DECLARE @dt AS DATE = '2018-11-09';
      WITH vars1 AS (
      SELECT
      d1 = DATEADD(dd, 1, EOMONTH(@dt, -1)),
      dn = EOMONTH(@dt),
      wks = DAY(@dt) / 7
      ), vars AS (
      SELECT
      d1, -- first day of month
      dn, -- last day of month
      wks, -- number of 7-day intervals elapsed
      d29 = DATEADD(dd, 28, d1), -- 29th day of month
      d30 = DATEADD(dd, 29, d1),
      d31 = DATEADD(dd, 30, d1),
      dp1 = DATEADD(dd, wks * 7 + 0, d1), -- wks * 7 gives you 0, 7, 14, 21 or 28
      dp2 = DATEADD(dd, wks * 7 + 1, d1), -- wks * 7 + 0 ... 5 are the dates to check
      dp3 = DATEADD(dd, wks * 7 + 2, d1),
      dp4 = DATEADD(dd, wks * 7 + 3, d1),
      dp5 = DATEADD(dd, wks * 7 + 4, d1),
      dp6 = DATEADD(dd, wks * 7 + 5, d1)
      FROM vars1
      )
      SELECT
      [no. of business days] = 20 +
      IIF(d29 <= dn AND DATENAME(dw, d29) NOT IN ('Saturday', 'Sunday'), 1, 0) +
      IIF(d30 <= dn AND DATENAME(dw, d30) NOT IN ('Saturday', 'Sunday'), 1, 0) +
      IIF(d31 <= dn AND DATENAME(dw, d31) NOT IN ('Saturday', 'Sunday'), 1, 0),
      [no. of business days passed] = wks * 5 +
      IIF(dp1 <= @dt AND DATENAME(dw, dp1) NOT IN ('Saturday', 'Sunday'), 1, 0) +
      IIF(dp2 <= @dt AND DATENAME(dw, dp2) NOT IN ('Saturday', 'Sunday'), 1, 0) +
      IIF(dp3 <= @dt AND DATENAME(dw, dp3) NOT IN ('Saturday', 'Sunday'), 1, 0) +
      IIF(dp4 <= @dt AND DATENAME(dw, dp4) NOT IN ('Saturday', 'Sunday'), 1, 0) +
      IIF(dp5 <= @dt AND DATENAME(dw, dp5) NOT IN ('Saturday', 'Sunday'), 1, 0) +
      IIF(dp6 <= @dt AND DATENAME(dw, dp6) NOT IN ('Saturday', 'Sunday'), 1, 0)
      FROM vars


      DB Fiddle






      share|improve this answer
























        up vote
        0
        down vote










        up vote
        0
        down vote









        You can do this without recursive CTE as long as you want data for a single month.



        • There are 20 working days in first 28 days on month. Just check 29, 30 and 31

        • There are 5 working days in first 7 days, 10 in 14 and so on. Just check 6 days.

        DECLARE @dt AS DATE = '2018-11-09';
        WITH vars1 AS (
        SELECT
        d1 = DATEADD(dd, 1, EOMONTH(@dt, -1)),
        dn = EOMONTH(@dt),
        wks = DAY(@dt) / 7
        ), vars AS (
        SELECT
        d1, -- first day of month
        dn, -- last day of month
        wks, -- number of 7-day intervals elapsed
        d29 = DATEADD(dd, 28, d1), -- 29th day of month
        d30 = DATEADD(dd, 29, d1),
        d31 = DATEADD(dd, 30, d1),
        dp1 = DATEADD(dd, wks * 7 + 0, d1), -- wks * 7 gives you 0, 7, 14, 21 or 28
        dp2 = DATEADD(dd, wks * 7 + 1, d1), -- wks * 7 + 0 ... 5 are the dates to check
        dp3 = DATEADD(dd, wks * 7 + 2, d1),
        dp4 = DATEADD(dd, wks * 7 + 3, d1),
        dp5 = DATEADD(dd, wks * 7 + 4, d1),
        dp6 = DATEADD(dd, wks * 7 + 5, d1)
        FROM vars1
        )
        SELECT
        [no. of business days] = 20 +
        IIF(d29 <= dn AND DATENAME(dw, d29) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(d30 <= dn AND DATENAME(dw, d30) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(d31 <= dn AND DATENAME(dw, d31) NOT IN ('Saturday', 'Sunday'), 1, 0),
        [no. of business days passed] = wks * 5 +
        IIF(dp1 <= @dt AND DATENAME(dw, dp1) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(dp2 <= @dt AND DATENAME(dw, dp2) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(dp3 <= @dt AND DATENAME(dw, dp3) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(dp4 <= @dt AND DATENAME(dw, dp4) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(dp5 <= @dt AND DATENAME(dw, dp5) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(dp6 <= @dt AND DATENAME(dw, dp6) NOT IN ('Saturday', 'Sunday'), 1, 0)
        FROM vars


        DB Fiddle






        share|improve this answer














        You can do this without recursive CTE as long as you want data for a single month.



        • There are 20 working days in first 28 days on month. Just check 29, 30 and 31

        • There are 5 working days in first 7 days, 10 in 14 and so on. Just check 6 days.

        DECLARE @dt AS DATE = '2018-11-09';
        WITH vars1 AS (
        SELECT
        d1 = DATEADD(dd, 1, EOMONTH(@dt, -1)),
        dn = EOMONTH(@dt),
        wks = DAY(@dt) / 7
        ), vars AS (
        SELECT
        d1, -- first day of month
        dn, -- last day of month
        wks, -- number of 7-day intervals elapsed
        d29 = DATEADD(dd, 28, d1), -- 29th day of month
        d30 = DATEADD(dd, 29, d1),
        d31 = DATEADD(dd, 30, d1),
        dp1 = DATEADD(dd, wks * 7 + 0, d1), -- wks * 7 gives you 0, 7, 14, 21 or 28
        dp2 = DATEADD(dd, wks * 7 + 1, d1), -- wks * 7 + 0 ... 5 are the dates to check
        dp3 = DATEADD(dd, wks * 7 + 2, d1),
        dp4 = DATEADD(dd, wks * 7 + 3, d1),
        dp5 = DATEADD(dd, wks * 7 + 4, d1),
        dp6 = DATEADD(dd, wks * 7 + 5, d1)
        FROM vars1
        )
        SELECT
        [no. of business days] = 20 +
        IIF(d29 <= dn AND DATENAME(dw, d29) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(d30 <= dn AND DATENAME(dw, d30) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(d31 <= dn AND DATENAME(dw, d31) NOT IN ('Saturday', 'Sunday'), 1, 0),
        [no. of business days passed] = wks * 5 +
        IIF(dp1 <= @dt AND DATENAME(dw, dp1) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(dp2 <= @dt AND DATENAME(dw, dp2) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(dp3 <= @dt AND DATENAME(dw, dp3) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(dp4 <= @dt AND DATENAME(dw, dp4) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(dp5 <= @dt AND DATENAME(dw, dp5) NOT IN ('Saturday', 'Sunday'), 1, 0) +
        IIF(dp6 <= @dt AND DATENAME(dw, dp6) NOT IN ('Saturday', 'Sunday'), 1, 0)
        FROM vars


        DB Fiddle







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 10 at 1:39

























        answered Nov 10 at 0:50









        Salman A

        172k65329415




        172k65329415



























             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53234712%2fcalculate-total-and-elapsed-number-of-working-days-in-the-month-for-a-given-date%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Use pre created SQLite database for Android project in kotlin

            Darth Vader #20

            Ondo