我有如下所示的表格,我想在每周的所有5周工作日内捕获员工是否工作。如果员工只工作3天,那么我想显示他/她工作的3天的工作时间,并为2个缺失的日子分配0:
UID DT HOURS_WORKED
Mike 07/4/16 5
Mike 07/5/16 8
Mike 07/7/16 4
这是此方案的预期结果
UID DT HOURS_WORKED
Mike 07/4/16 5
Mike 07/5/16 8
Mike 06/6/16 0
Mike 07/7/16 4
Mike 07/8/16 0
所以当他们跳过当天的工作时我想把0。我不想显示周末。谢谢你的帮助
select UID, DT, HOURS_WORKED from my table
答案 0 :(得分:1)
构建一个日期cte,其中包含一周内的所有日期,并在此表上执行外部联接,以便在员工在给定工作日不工作时显示0
。
with x as (select cast('2016-07-01' as date) dt
union all
select dateadd(dd,1,dt) from x where dt < '2016-07-31')
select e.uid, t.dt, coalesce(e.hours_worked,0) hours_worked
from (select * from x where datepart(dw,dt) between 2 and 6) t
left join emp_table e on e.dt = t.dt
答案 1 :(得分:1)
我增强了@vkp的答案,使其更通用,(如果你真的很挑剔我们需要处理边缘情况,在第一周或上周的某些天可能会落入不同年份)
在这里,我添加了使用Datefirst设置更改一周的第一天的功能。更多关于Datefirst MSDN:https://msdn.microsoft.com/en-us/library/ms181598.aspx
/* Setup Test Data
Drop Table #T1
Create Table #T1 ( UID Varchar(10), Dt Date, Hrs int )
insert into #T1 Values
( 'Mike' , GetDate() , 8 ) , -- Sat 07/23
( 'Mike' , GetDate()-1 , 8 ) ,
( 'Mike' , GetDate()-2 , 8 ) ,
( 'Mike' , GetDate()+3 , 8 ) -- Tue 07/26
( 'John' , GetDate() , 8 ) , -- Sat 07/23
( 'John' , GetDate()-1 , 8 ) ,
( 'John' , GetDate()-2 , 8 ) ,
( 'John' , GetDate()+3 , 8 )
insert into #T1 Values
( 'Mike' , GetDate() - 206 , 8 ) , --- One Date for Last Year 12/30 to Test Edge Case
-- select * , DatePart( WEEK, Dt) from #T1
*/
- 创建帮助电视功能以获取一年中某一周的日期
ALTER FUNCTION GetDates
(
@WK int ,
@yr varchar(5) = ''
)
RETURNS
@Table_Var TABLE
(
DD int,
Dt Date,
Wk int
)
AS
BEGIN
IF @yr = '' SET @yr = YEAR(Getdate()) -- If Year is Blank then Default to current year
Declare @LastDateOfYr Date = RTRIM(@YR)+'-12-31' -- Last Day of the year
Declare @LastDayOfYr Int = CAST(Datename(dy, @LastDateOfYr ) as int) -- No.of Days in the Year to Handle Leap Yrs
;WITH Dates as
(
-- SELECT 0 as DD , DATEADD(D, 0, @yr ) as Dt , DatePart( WEEK, DATEADD(D, 0 , @yr )) as Wk
SELECT Datepart( DAYOFYEAR,DateAdd(D, (@WK-2)*7, @yr) ) as DD , DATEADD(D, (@WK-2)*7, @yr ) as Dt , @WK-2 as Wk -- Initial values for the Recursive CTE.
UNION ALL
SELECT Dates.DD+1 as DD , DATEADD(D, Dates.DD, @yr ) , DatePart( WEEK,DATEADD(D, Dates.DD, @yr )) from Dates where Dates.DD <= @LastDayOfYr
AND Wk <= @WK + 1 -- Terminator for Recursion
)
INSERT INTO @Table_Var
SELECT
DD ,
Dt ,
Wk
FROM Dates as A
WHERE A.Wk = @WK
OPTION (MAXRECURSION 21) -- At any point we dont use CTE For more than 3 Weeks (one week actually). If the CTE is changed by using the commented out Initializer inside the CTE Above then this number has to change accordingly
RETURN
END
GO
查询:
SET DATEFIRST 1 -- Make Monday as First Day of Week. The default is Sunday.
Select B.* , A.* , ISNULL(T.Hrs,0) Hours_Worked
FROM
( SELECT Distinct UID,
DatePart( WEEK, Dt) as WK ,
DatePart( YEAR, Dt) as Yr
FROM #T1
) A
CROSS APPLY dbo.GetDates(A.WK, A.Yr ) B -- Helper Function Used to apply
LEFT OUTER JOIN #T1 T ON B.Dt = T.Dt