2016-07-22 4 views
-1

나는 아래와 같은 테이블을 가지고 있으며 직원이 근무했는지 여부와 상관없이 매주 5 주일을 포착하고자합니다.주당 근무 시간 계산 및 SQL을 사용하여 주말 제외

여기
UID  DT   HOURS_WORKED 
Mike  07/4/16   5 
Mike  07/5/16   8 
Mike  07/7/16   4 

이 시나리오

에 대해 원하는 결과입니다 : 직원이 불과 3 일을 일하면, 나는 그/그녀가 근무하고 2 누락 된 일에 대해 0을 할당하는 것이 3 일 동안 시간을 ​​보여주고 싶은
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

나는

(당신이 정말로 까다로운 경우 우리는 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 
*/ 

- 1 년에 주어진 주에 대한 날짜를 얻을 수있는 도우미 TV 기능 만들기

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 
+0

감사합니다. 그러나 여러 명의 사용자가 있고 숫자가 제대로 표시되지 않으면이 기능이 작동하지 않습니다. – moe

+0

@moe 많은 변경을했습니다 ... 지금보십시오 – objectNotFound

+0

출력 쿼리에서이 필드 DD는 무엇입니까? 나는 그것을 구현하기 전에 지금 그것을 이해하려고 노력하고있다. 다시 고마워요 – moe

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 
+0

감사합니다. vip, 여기 괄호는 무엇입니까? x에서 dateadd (dd, 1, dt)를 선택하십시오. 여기서 dt < '2016-07-31') – moe

+0

은 'cte'의 끝을 나타냅니다. –