2012-07-22 1 views
1

따라서 조종사는 매 6 개월 (준결승) 및 매년 (연간) 너무 많은 비행 시간과 비행 소총을 얻어야합니다. 가장 큰 고통은이 기간의 시작일과 종료일이 출생 월을 기준으로한다는 것입니다.조종사 생일과 현재 날짜를 기준으로 SQL 날짜를 계산하는 방법

당신은 여기 내 스키마에 대한 자세한 정보를 찾을 수 있습니다 : Design decision: Table schema for partial dates in order to calculate time spans (SQL Server)

DECLARE @date Date 
SET @date = '1985-04-12' 

DECLARE @diffInYears INT 
SET @diffInYears = DATEDIFF(yy, @date, GETDATE()) 

DECLARE @currentBirthDate Date 
SET @currentBirthDate = (SELECT dateadd(yyyy, @diffInYears, @date)) 

SELECT DATEADD(dd, -DAY(DATEADD(m,1,@currentBirthDate)), DATEADD(m,7,@currentBirthDate)) semiAnnualDateEnd, 
     DATEADD(dd, -DAY(DATEADD(m,1,@currentBirthDate)), DATEADD(m,13,@currentBirthDate)) annualDateEnd 

RESULTS: 

semiAnnualDateEnd - annualDateEnd 
    2012-10-31  - 2013-04-30 

지금,이 중대하다,이 내가이 특정 예를 들어 원하는 날짜입니다.

그러나 2012 년 11 월 1 일에 도착하면 semiAnnualDateEnd가 2013-04-30이되기를 바랍니다.

2013 년 1 월 1 일이되면 (2013 년 1 월 1 일) 2013-05-01까지 2013D4-30에 머무르고 싶을 때 annualDateEnd는 2014-04-30이 될 것입니다. 그런 다음 2014-04-30 (semiAnnual의 경우와 비슷한 상황)이됩니다.

저는이 날짜를 특정 조종사와 정적으로 연관 짓기를 원하지 않습니다. 즉, 파일럿 테이블에 이러한 필드가있는 필드를 두 개 유지하고 싶지 않습니다. 그러나, 나는 이것을 디스플레이와 계산에 사용하고 싶다. 예를 들어, 각 조종사의 현재 반년 및 연별 출근과 비행 시간을 표시하고 특정 시점의 "현재"통계를 스냅 샷으로 표시해야 할 필요가 있습니다.

편집 : SQL Server 2008 Express에 RC를 사용하고

편집 2 :. 내가 (SELECT DATEADD (YYYY, @diffInYears에 @currentBirthDate 변경해야합니다 생각하고 있어요 -) @date 1 다음, 나는 (계속 실험)

답변

0
DECLARE @pilotID INT 
SET @pilotID = 1 

DECLARE @birthDate DATE 
SET @birthDate = (SELECT birthDate FROM Pilot WHERE pilotID = @pilotID) 

DECLARE @diffInYears INT 
SET @diffInYears = DATEDIFF(yy, @birthDate, GETDATE()) 

DECLARE @currentBirthDate DATE 
SET @currentBirthDate = (DATEADD(yyyy, @diffInYears - 1, @birthDate)) 

DECLARE @firstSixMonthStart DATE 
DECLARE @firstSixMonthEnd DATE 
DECLARE @secondSixMonthStart DATE 
DECLARE @secondSixMonthEnd DATE 

SET @firstSixMonthStart = (DATEADD(dd,-(DAY(DATEADD(m,1,@currentBirthDate))-1),DATEADD(m,1,@currentBirthDate))) 
SET @firstSixMonthEnd = (DATEADD(dd, -DAY(DATEADD(m,1,@currentBirthDate)), DATEADD(m,7,@currentBirthDate))) 
SET @secondSixMonthStart = (DATEADD(dd,-(DAY(DATEADD(m,1,@currentBirthDate))-1),DATEADD(m,7,@currentBirthDate))) 
SET @secondSixMonthEnd = (DATEADD(dd, -DAY(DATEADD(m,1,@currentBirthDate)), DATEADD(m,13,@currentBirthDate))) 


DECLARE @semiAnnualStart AS DATE 
DECLARE @semiAnnualEnd AS DATE 
DECLARE @annualStart AS DATE 
DECLARE @annualEnd AS DATE 

SET @semiAnnualStart = CASE 
          WHEN GETDATE() > (DATEADD(dd, -DAY(DATEADD(m,1,@firstSixMonthEnd)), DATEADD(m,7,@firstSixMonthEnd))) 
           THEN (DATEADD(yyyy, 1, @firstSixMonthStart)) 
          WHEN GETDATE() > @firstSixMonthEnd 
           THEN @secondSixMonthStart  
          ELSE @firstSixMonthStart 
         END  

SET @semiAnnualEnd = CASE 
          WHEN GETDATE() > (DATEADD(dd, -DAY(DATEADD(m,1,@firstSixMonthEnd)), DATEADD(m,7,@firstSixMonthEnd))) 
           THEN (DATEADD(yyyy, 1, @firstSixMonthEnd)) 
          WHEN GETDATE() > @firstSixMonthEnd 
           THEN @secondSixMonthEnd  
          ELSE @firstSixMonthEnd 
         END  

SET @annualStart =  CASE 
          WHEN GETDATE() > @secondSixMonthEnd THEN (DATEADD(yyyy, 1, @firstSixMonthStart)) 
          ELSE @firstSixMonthStart 
         END   

SET @annualEnd =  CASE 
          WHEN GETDATE() > @secondSixMonthEnd THEN (DATEADD(yyyy, 1, @secondSixMonthEnd)) 
          ELSE @secondSixMonthEnd 
         END 

SELECT @semiAnnualStart semiStart, @semiAnnualEnd semiEnd, 
     @annualStart annualStart, @annualEnd annualEnd, 
     @firstSixMonthStart firstStart, @firstSixMonthEnd firstEnd, 
     @secondSixMonthStart secondStart, @secondSixMonthEnd secondEnd, 
     COUNT(*) semiSorties, ISNULL(SUM(hours), 0) semiSortieHours 
FROM PilotLog 
WHERE pilotID = @pilotID 
    AND topLevelPosition = 'AVO' 
    AND flightDate BETWEEN @semiAnnualStart AND @semiAnnualEnd 

결과 아래의 경우 문을 수행해야이 작동 결국

semiStart semiEnd  annualStart annualEnd firstStart firstEnd secondStart secondEnd semiSorties semiSortieHours 
2012-05-01 2012-10-31 2011-11-01 2012-10-31 2011-11-01 2012-04-30 2012-05-01 2012-10-31 1   1.7 

... 문제는, 나는 모든 파일럿이 작업을 수행 할 필요 해요 전체적으로 정상 페이지. 또한 필자는 원하는 스냅 샷에 대해 이러한 종류의 정보를 계산할 필요가 있습니다. 그녀는 특정 달로 돌아가서 스냅 샷을보고 각 항공편과 해당 항공편을 완료 할 때 있었던 출장 통계를 표시하려고합니다. 이 SQL은 이러한 상황에서 작동해야합니다. 여기저기서 조금 변경해야합니다.

:

1

반 연간 날짜에 대한 규칙이 될 것으로 보인다 (EDIT?. 바로 인터넷 익스플로러의 수평 나의 코드 스크롤을하지 왜 .. 나는 그것을 포장하고 싶지 않아 신경 끄시는 모양) : 달에 5 개월을 더하고 달의 마지막에 가십시오. 월말에 문제가 생길 수 있습니다. 따라서 이것을 "6 개월 추가, 월말에 도달하고 1 일 빼기"로 변경하십시오. (나는 당신의 예에서이 논리를 근거로하고있다.)

다음과 같은 표현이 수행합니다 날짜

그것은 년에 날짜 연산을 수행
select dateadd(d, -1, 
       cast(cast(year(bd)+(case when month(bd)+6 > 12 then 1 else 0 end) as varchar(255))+'-'+ 
        cast(case when month(bd)+7> 12 then month(bd)+6-12 else month(bd) end as varchar(255))+'-'+ 
        '1' as date)) 
from (select cast('2011-11-01' as date) bd) t 

()와 달() 값. 그런 다음 문자열로 다시 gloms, 날짜로 변환하고 1 일을 뺍니다.

나는 비슷한 것이 당신의 연중 날짜에도 효과가 있다고 생각합니다.

+0

이번 달 초에 가서 1 일을 뺀다는 의미였습니까? 또한 단지 까다 롭지 만 실제로 varchar (255)로 캐스팅해야합니까?그 해 동안 varchar (4)를 할 수 없었으며 그 달에 (2) 할 수 없었습니까? – Greg

+1

예, 저는이 달 초에 가서 하루를 빼기로했습니다. 이 달의 끝을 찾는 가장 쉬운 방법입니다. varchar의 크기는 충분히 크고 <= 8000이면 쿼리 성능에 아무런 영향을 미치지 않습니다. 특별한 가치는 개인적인 취향의 문제입니다. –