每周计算工作日

时间:2018-05-28 08:01:56

标签: sql sql-server tsql

我想计算一个月内一周内的工作天数。我写了这个查询,这可以让我得到日期和日期,但我无法将它们分成几周。

以下是查询:

DECLARE @intEmployeeCode INT = 2309
DECLARE @StartDate datetime;
DECLARE @EndDate datetime;

DECLARE @Month int
DECLARE @Year int

SET @Month = month(getdate())
SET @Year = year(getdate())

SET @StartDate = (select DATEADD(month,month(getdate())-1,DATEADD(year,year(getdate())-1900,0)) ) /*First*/
SET @EndDate = (select DATEADD(day,-1,DATEADD(month,@Month,DATEADD(year,@Year-1900,0))) )/*Last*/


;WITH cte AS (
    SELECT 
    CAST(CAST (@StartDate AS NVARCHAR) AS date) AS myDate
    UNION ALL
    SELECT DATEADD(day,1,myDate) as myDate

    FROM cte
    WHERE DATEADD(day,1,myDate) <= CAST(CAST (@EndDate AS NVARCHAR) AS date))

SELECT myDate ,datename(dw,myDate) AS DayOfDate
FROM cte 
WHERE datename(dw,myDate) <> 'Sunday'
OPTION (MAXRECURSION 0);

预期结果:

Week Number  Working Days
Week 1       5
Week 2       6
Week 3       6
Week 4       6
Week 5       4

2 个答案:

答案 0 :(得分:2)

试试这个(代码注释):

DECLARE @intEmployeeCode INT = 2309
DECLARE @StartDate date;
DECLARE @EndDate date;
--I changed your code a little, removed unnecessary variables
--below always returns first and last day of current month
SET @StartDate = DATEADD(dd, -(DATEPART(dd, GETDATE()) - 1), getdate())
SET @EndDate = DATEADD(dd, -1,DATEADD(mm, 1, @StartDate))

;WITH cte AS (
    SELECT @StartDate as myDate
    UNION ALL
    SELECT DATEADD(day,1,myDate) as myDate
    FROM cte
    WHERE DATEADD(day,1,myDate) <= CAST(CAST (@EndDate AS NVARCHAR) AS date)
)
--in subquery we generate additional column to group by week :)
--we also keep column indicating non-working day, Sunday
select weekGroup + 1 [WeekNumber],
       COUNT(*) [WorkingDays]
from (
    SELECT myDate,
           --here you specify non-working days, now they are sunday - 1 and saturday - 6
           case when DATEPART(dw, myDate) in (1,6) then 1 else 0 end isNonWorkingDay,
           sum(case DATEPART(dw, myDate) when 1 then 1 else 0 end) over (partition by (select null) order by myDate rows between unbounded preceding and current row) weekGroup
    FROM cte 
) [a]
where isNonWorkingDay = 0
group by weekGroup 
OPTION (MAXRECURSION 0);

答案 1 :(得分:1)

应该可以通过DatePart来实现,如下所示:

DECLARE @intEmployeeCode INT = 2309
DECLARE @StartDate datetime;
DECLARE @EndDate datetime;

DECLARE @Month int
DECLARE @Year int

SET @Month = month(getdate()) + 2
SET @Year = year(getdate())

SET @StartDate = (select DATEADD(month,month(getdate())-1,DATEADD(year,year(getdate())-1900,0)) ) /*First*/
SET @EndDate = (select DATEADD(day,-1,DATEADD(month,@Month,DATEADD(year,@Year-1900,0))) )/*Last*/


;WITH cte AS (
    SELECT 
    CAST(CAST (@StartDate AS NVARCHAR) AS date) AS myDate
    UNION ALL
    SELECT DATEADD(day,1,myDate) as myDate

    FROM cte
    WHERE DATEADD(day,1,myDate) <= CAST(CAST (@EndDate AS NVARCHAR) AS date)
),
cteWeekwise AS(
SELECT myDate ,datename(dw,myDate) AS DayOfDate, DATEPART(YEAR, myDate) cwYear, DATEPART(MONTH, myDate) cwMonth, DATEPART(WEEK, myDate) cw, DENSE_RANK() OVER(PARTITION BY DATEPART(YEAR, myDate), DATEPART(MONTH, myDate) ORDER BY DATEPART(WEEK, myDate)) WeekIdx
FROM cte 
WHERE datename(dw,myDate) <> 'Sunday'
)
SELECT WeekIdx, cwYear, cwMonth, cw, COUNT(*) cnt
  FROM cteWeekwise
  --
  WHERE cwYear = 2018
    AND cwMonth = 5
    AND WeekIdx = 5
  --
  GROUP BY cwYear, cwMonth, cw, WeekIdx
  ORDER BY cwYear, cwMonth, cw
OPTION (MAXRECURSION 0);