programing

SQL에서 두 날짜 사이의 전체 월 수 계산

bestprogram 2023. 6. 26. 21:29

SQL에서 두 날짜 사이의 전체 월 수 계산

SQL의 FULL month 를 계산해야 합니다.

  • 2009-04-16 ~ 2009-05-15 => 0 보름.
  • 2009-04-16 ~ 2009-05-16 => 1개월 내내
  • 2009-04-16 ~ 2009-06-16 => 꼬박 2개월

저는 DATEIFF를 사용하려고 했습니다.

SELECT DATEDIFF(MONTH, '2009-04-16', '2009-05-15')

하지만 두 날짜 사이에 꼬박 한 달을 주는 대신 월 부분의 차이를 제공합니다.

1

SQL Server의 전체 달 수를 계산하는 방법을 아는 사람?

원래 게시물에 버그가 있었습니다...그래서 다시 작성해서 UDF로 포장했습니다.

CREATE FUNCTION FullMonthsSeparation 
(
    @DateA DATETIME,
    @DateB DATETIME
)
RETURNS INT
AS
BEGIN
    DECLARE @Result INT

    DECLARE @DateX DATETIME
    DECLARE @DateY DATETIME

    IF(@DateA < @DateB)
    BEGIN
        SET @DateX = @DateA
        SET @DateY = @DateB
    END
    ELSE
    BEGIN
        SET @DateX = @DateB
        SET @DateY = @DateA
    END

    SET @Result = (
                    SELECT 
                    CASE 
                        WHEN DATEPART(DAY, @DateX) > DATEPART(DAY, @DateY)
                        THEN DATEDIFF(MONTH, @DateX, @DateY) - 1
                        ELSE DATEDIFF(MONTH, @DateX, @DateY)
                    END
                    )

    RETURN @Result
END
GO

SELECT dbo.FullMonthsSeparation('2009-04-16', '2009-05-15') as MonthSep -- =0
SELECT dbo.FullMonthsSeparation('2009-04-16', '2009-05-16') as MonthSep -- =1
SELECT dbo.FullMonthsSeparation('2009-04-16', '2009-06-16') as MonthSep -- =2
select case when DATEPART(D,End_dATE) >=DATEPART(D,sTAR_dATE) 
THEN ( case when DATEPART(M,End_dATE) = DATEPART(M,sTAR_dATE) AND DATEPART(YYYY,End_dATE) = DATEPART(YYYY,sTAR_dATE) 
        THEN 0 ELSE DATEDIFF(M,sTAR_dATE,End_dATE)END )
ELSE DATEDIFF(M,sTAR_dATE,End_dATE)-1 END

한 달의 정의는 무엇입니까?기술적으로 한 달은 월과 윤년에 따라 28, 29, 30일 또는 31일이 될 수 있습니다.

당신의 예에서 5월에 31일이 있다는 것을 무시했기 때문에 한 달을 30일로 생각하는 것 같은데, 다음과 같이 하면 어떨까요?

SELECT DATEDIFF(DAY, '2009-04-16', '2009-05-15')/30
    , DATEDIFF(DAY, '2009-04-16', '2009-05-16')/30
    , DATEDIFF(DAY, '2009-04-16', '2009-06-16')/30

날짜 추가 기능을 사용하여 월초로 오프셋할 수 있습니다.endDate의 날짜 부분이 startDate보다 작은 경우, 이전 달로 밀리기 때문에 datediff는 정확한 월 수를 제공합니다.

DATEDIFF(MONTH, DATEADD(DAY,-DAY(startDate)+1,startDate),DATEADD(DAY,-DAY(startDate)+1,endDate))

이는 Oracle 전용이며 SQL-Server용이 아닙니다.

months_between(to_date ('2009/05/15', 'yyyy/mm/dd'), 
               to_date ('2009/04/16', 'yyyy/mm/dd'))

그리고 한 달 동안:

round(months_between(to_date ('2009/05/15', 'yyyy/mm/dd'), 
                     to_date ('2009/04/16', 'yyyy/mm/dd')))

Oracle 8i 이상에서 사용할 수 있습니다.

오래된 질문인 것은 알지만 날짜가 >= 01-Jan-1753인 한 다음을 사용합니다.

DATEDIFF(MONTH, DATEADD(DAY,-DAY(@Start)+1,@Start),DATEADD(DAY,-DAY(@Start)+1,@End))

DATEIFF()는 지정된 기간 동안 두 날짜 사이에 교차된 숫자 경계를 반환하도록 설계되었습니다.원하는 작업을 수행하려면 날짜가 경계를 넘지만 전체 범위를 완료하지 않은 경우를 고려하여 추가로 조정해야 합니다.

WITH   
-- Count how many months must be added to @StartDate to exceed @DueDate  
MONTHS_SINCE(n, [Month_hence], [IsFull], [RemainingDays] ) AS (  
SELECT   
    1 as n,  
    DATEADD(Day, -1, DATEADD(Month, 1, @StartDate)) AS Month_hence  
    ,CASE WHEN (DATEADD(Day, -1, DATEADD(Month, 1, @StartDate)) <= @LastDueDate)   
        THEN 1   
        ELSE 0   
    END  AS [IsFull]  
    ,DATEDIFF(day, @StartDate,  @LastDueDate) as [RemainingDays]  
UNION ALL  
SELECT  
    n+1,  
    --DateAdd(Month, 1, Month_hence) as Month_hence -- No, causes propagation of short month discounted days  
    DATEADD(Day, -1, DATEADD(Month, n+1, @StartDate)) as Month_hence  
    ,CASE WHEN (DATEADD(Day, -1, DATEADD(Month, n+1, @StartDate)) <= @LastDueDate)   
        THEN 1   
        ELSE 0    
    END  AS [IsFull]  
    ,DATEDIFF(day, DATEADD(Day, -1, DATEADD(Month, n, @StartDate)),  @LastDueDate)  
    FROM MONTHS_SINCE   
    WHERE Month_hence<( @LastDueDate --WHERE Period= 1  
    )  
), --SELECT * FROM MONTHS_SINCE  
MONTH_TALLY (full_months_over_all_terms, months_over_all_terms, days_in_incomplete_month ) AS (  
SELECT  
    COALESCE((SELECT MAX(n) FROM MONTHS_SINCE WHERE isFull = 1),1) as full_months_over_all_terms,  
    (SELECT MAX(n) FROM MONTHS_SINCE ) as months_over_all_terms,  
    COALESCE((SELECT [RemainingDays] FROM MONTHS_SINCE WHERE isFull = 0),0) as days_in_incomplete_month  
) SELECT * FROM MONTH_TALLY;   

@결과 부분만 함수를 생성할 필요는 없습니다.예:

Select Name,
(SELECT CASE WHEN 
DATEPART(DAY, '2016-08-28') > DATEPART(DAY, '2016-09-29')   
THEN DATEDIFF(MONTH, '2016-08-28',  '2016-09-29') - 1
ELSE DATEDIFF(MONTH, '2016-08-28',  '2016-09-29') END) as NumberOfMonths

FROM 
tableExample;

이 답변은 T-SQL 형식을 따릅니다.저는 이 문제를 날짜 시간 형식의 두 날짜 지점 사이의 선형 시간 거리 중 하나로 개념화합니다.이를 Time1 및 Time2라고 부릅니다. Time1은 현재 처리 중인 '이전 시간' 값(예: 생년월일 또는 위젯 작성 날짜 또는 여정 시작 날짜)에 맞춰져야 하며 Time2는 '새로운 시간' 값(예: 스냅샷 날짜 또는 위젯 완료 날짜 또는 여정 체크포인트에 도달한 날짜)에 맞춰져야 합니다.

DECLARE @Time1 DATETIME
SET @Time1 = '12/14/2015'

DECLARE @Time2 DATETIME
SET @Time2 = '12/15/2016'

이 솔루션은 다양한 길이의 여러 사이클의 직렬 교차점에 대한 간단한 측정, 변환 및 계산을 활용합니다. 여기서는 Century, Decade,년, 월, 일 (Mayan Calendar 컨셉 감사합니다!간단한 감사의 말씀을 전합니다.Stack Overflow의 다른 기여자들에게 이 프로세스의 일부 구성 요소 기능을 보여주셔서 감사합니다.저는 이 포럼에서 이것들을 긍정적으로 평가했습니다.

먼저, 세기, 십년, 십년의 교차점들의 선형 집합인 수평선을 구축합니다.연도, 월 주기, 월 단위로 증분합니다.교차 결합 데카르트 함수를 사용합니다.(거리를 측정하기 위해 두 'yyyy-mm' 지점 사이의 길이를 자를 천을 만드는 것으로 간주합니다.)

SELECT 
Linear_YearMonths = (centuries.century + decades.decade + years.[year] + months.[Month]),
1 AS value
INTO #linear_months
FROM
(SELECT '18' [century] UNION ALL
SELECT '19' UNION ALL
SELECT '20') centuries 
CROSS JOIN 
(SELECT '0' [decade] UNION ALL
SELECT '1' UNION ALL
SELECT '2' UNION ALL
SELECT '3' UNION ALL
SELECT '4' UNION ALL
SELECT '5' UNION ALL
SELECT '6' UNION ALL
SELECT '7' UNION ALL
SELECT '8' UNION ALL
SELECT '9') decades 
CROSS JOIN 
(SELECT '1' [year] UNION ALL
SELECT '2' UNION ALL
SELECT '3' UNION ALL
SELECT '4' UNION ALL
SELECT '5' UNION ALL
SELECT '6' UNION ALL
SELECT '7' UNION ALL
SELECT '8' UNION ALL
SELECT '9' UNION ALL
SELECT '0') years 
CROSS JOIN  
(SELECT '-01' [month] UNION ALL
SELECT '-02' UNION ALL
SELECT '-03' UNION ALL
SELECT '-04' UNION ALL
SELECT '-05' UNION ALL
SELECT '-06' UNION ALL
SELECT '-07' UNION ALL
SELECT '-08' UNION ALL
SELECT '-09' UNION ALL
SELECT '-10' UNION ALL
SELECT '-11' UNION ALL
SELECT '-12') [months]
ORDER BY 1

그런 다음 Time1 및 Time2 날짜 점을 'yyyy-mm' 형식으로 변환합니다(이것들을 전체 천의 좌표 절단점으로 생각).점의 원래 날짜/시간 버전도 유지합니다.

SELECT
Time1 = @Time1,
[YYYY-MM of Time1] = CASE
WHEN LEFT(MONTH(@Time1),1) <> '1' OR MONTH(@Time1) = '1'
    THEN (CAST(YEAR(@Time1) AS VARCHAR) + '-' + '0' + CAST(MONTH(@Time1) AS VARCHAR))
    ELSE (CAST(YEAR(@Time1) AS VARCHAR) + '-' + CAST(MONTH(@Time1) AS VARCHAR))
    END,
Time2 = @Time2,
[YYYY-MM of Time2] = CASE
WHEN LEFT(MONTH(@Time2),1) <> '1' OR MONTH(@Time2) = '1'
    THEN (CAST(YEAR(@Time2) AS VARCHAR) + '-' + '0' + CAST(MONTH(@Time2) AS VARCHAR))
    ELSE (CAST(YEAR(@Time2) AS VARCHAR) + '-' + CAST(MONTH(@Time2) AS VARCHAR))
    END
INTO #datepoints

그런 다음 'yyyyy-mm' 단위의 서수 거리를 선택하고 기본 거리로 변환할 1개 미만을 선택합니다(즉, 식별된 절단 지점에서 전체 천에서 천을 잘라 원시 측정값을 얻습니다).

SELECT 
d.*,
Months_Between = (SELECT (SUM(l.value) - 1) FROM #linear_months l
            WHERE l.[Linear_YearMonths] BETWEEN d.[YYYY-MM of Time1] AND d.[YYYY-MM of Time2])
FROM #datepoints d

원시 출력:'yyyy-mm' 기본 거리의 월 성분이 너무 많을 수 있기 때문에 이를 '원거리'라고 합니다. 이 마지막 달 값을 계산해야 하는지 여부를 확인하려면 해당 달 내의 일 주기 성분을 비교해야 합니다.구체적으로 이 예에서 원시 출력 거리는 '12'입니다.그러나 12월 14일이 12월 15일 이전이기 때문에 11개월만 경과했습니다. 즉, 12월을 하루 앞두고 있습니다.따라서 우리는 최종 답변에 도달하기 위해 한 달 내 일일 주기를 가져와야 합니다.사이에 '월, 일' 위치 비교를 삽입하여 최신 날짜 포인트 월이 명목상으로 카운트되는지 여부를 확인합니다.

SELECT 
d.*,
Months_Between = (SELECT (SUM(l.value) - 1) FROM AZ_VBP.[MY].[edg_Linear_YearMonths] l
            WHERE l.[Linear_YearMonths] BETWEEN d.[YYYY-MM of Time1] AND d.[YYYY-MM of Time2])
        + (CASE WHEN DAY(Time1) < DAY(Time2)
                THEN -1
                ELSE 0
                END)
FROM #datepoints d

최종 출력:이제 '11'의 정답은 우리의 출력입니다.그래서 저는 이것이 도움이 되기를 바랍니다.감사합니다!

select CAST(DATEDIFF(MONTH, StartDate, EndDate) AS float) -
  (DATEPART(dd,StartDate) - 1.0) / DATEDIFF(DAY, StartDate, DATEADD(MONTH, 1, StartDate)) +
  (DATEPART(dd,EndDate)*1.0 ) / DATEDIFF(DAY, EndDate, DATEADD(MONTH, 1, EndDate))

이것이 오래된 게시물이라는 것을 알고 있지만, 저는 CASE 문장을 사용하여 쉽게 구현할 수 있는 흥미로운 솔루션을 만들었습니다.

DATEIFF를 사용하여 차이를 추정한 다음 DATEADD를 사용하기 전과 후의 달을 테스트하여 최적의 날짜를 찾습니다.이것은 1월 31일부터 2월 28일까지(그렇기 때문에) 1개월로 가정합니다.

DECLARE @First date = '2015-08-31'
DECLARE @Last date = '2016-02-28'

SELECT
    @First as [First],
    @Last as [Last],
    DateDiff(Month, @First, @Last) as [DateDiff Thinks],
    CASE
        WHEN DATEADD(Month, DATEDIFF(Month, @First, @Last) +1, @First) <= @Last Then DATEDIFF(Month, @First, @Last) +1
        WHEN DATEADD(Month, DATEDIFF(Month, @First, @Last) , @First) <= @Last Then DATEDIFF(Month, @First, @Last) 
        WHEN DATEADD(Month, DATEDIFF(Month, @First, @Last) -1, @First) <= @Last Then DATEDIFF(Month, @First, @Last) -1
    END as [Actual Months Apart]

간단하고 쉬운 방법으로 이 전체 코드를 복사하여 MS SQL에 붙여넣고 실행:

declare @StartDate date='2019-01-31'
declare @EndDate date='2019-02-28'


SELECT

DATEDIFF(MONTH, @StartDate, @EndDate)+

(

case 

when format(@StartDate,'yyyy-MM') != format(@EndDate,'yyyy-MM') AND DATEPART(DAY,@StartDate) > DATEPART(DAY,@EndDate) AND DATEPART(DAY,@EndDate) = DATEPART(DAY,EOMONTH(@EndDate)) then 0

when format(@StartDate,'yyyy-MM') != format(@EndDate,'yyyy-MM') AND DATEPART(DAY,@StartDate) > DATEPART(DAY,@EndDate)  then -1 

else 0 

end

) 

as NumberOfMonths

종료일이 시작일에서 해당 월의 날짜를 아직 지나지 않은 경우 추가 월을 공제하기만 하면 됩니다.

DECLARE @StartDate AS DATE = '2019-07-17'
DECLARE @EndDate AS DATE = '2019-09-15'


DECLARE @MonthDiff AS INT = DATEDIFF(MONTH,@StartDate,@EndDate)

SELECT @MonthDiff - 
        CASE 
            WHEN FORMAT(@StartDate,'dd') > FORMAT(@EndDate,'dd') THEN 1
            ELSE 0
        END

이 함수를 생성하여 두 날짜 간의 절대 차이를 계산할 수 있습니다.제가 DATEIFF 내장 시스템 기능을 사용하는 것을 발견했기 때문에, 몇 개월, 며칠, 몇 년 안에 차이가 날 것입니다.예를 들어, 18-Jan-2018 날짜와 15-Jan-2019 날짜가 있다고 가정합니다.그래서 그 날짜들 사이의 차이는 12개월로 DATEIFF에 의해 12개월로 주어질 것이고, 실제로는 11개월 28일입니다.그래서 아래의 함수를 사용하여, 우리는 두 날짜 사이의 절대적인 차이를 찾을 수 있습니다.

CREATE FUNCTION GetDurationInMonthAndDays(@First_Date DateTime,@Second_Date DateTime)

RETURNS VARCHAR(500)

AS

BEGIN

    DECLARE @RESULT VARCHAR(500)=''



    DECLARE @MONTHS TABLE(MONTH_ID INT,MONTH_NAME VARCHAR(100),MONTH_DAYS INT)

    INSERT INTO @MONTHS

    SELECT 1,'Jan',31

    union SELECT 2,'Feb',28

    union SELECT 3,'Mar',31

    union SELECT 4,'Apr',30

    union SELECT 5,'May',31

    union SELECT 6,'Jun',30

    union SELECT 7,'Jul',31

    union SELECT 8,'Aug',31

    union SELECT 9,'Sep',30

    union SELECT 10,'Oct',31

    union SELECT 11,'Nov',30

    union SELECT 12,'Jan',31



    IF(@Second_Date>@First_Date)

    BEGIN



            declare @month int=0

            declare @days int=0



            declare @first_year int

            declare @second_year int



            SELECT @first_year=Year(@First_Date)

            SELECT @second_year=Year(@Second_Date)+1



            declare @first_month int

            declare @second_month int



            SELECT @first_month=Month(@First_Date)

            SELECT @second_month=Month(@Second_Date)    



            if(@first_month=2)

            begin

                   IF((@first_year%100<>0) AND (@first_year%4=0) OR (@first_year%400=0))

                     BEGIN

                      SELECT @days=29-day(@First_Date) 

                     END

                   else

                     begin

                      SELECT @days=28-day(@First_Date) 

                     end

            end

            else

            begin

              SELECT @days=(SELECT MONTH_DAYS FROM @MONTHS WHERE MONTH_ID=@first_month)-day(@First_Date) 

            end



            SELECT @first_month=@first_month+1



            WHILE @first_year<@second_year

            BEGIN

               if(@first_month=13)

               begin

                set @first_month=1

               end

               WHILE @first_month<13

               BEGIN

                   if(@first_year=Year(@Second_Date))

                   begin

                    if(@first_month=@second_month)

                    begin           

                     SELECT @days=@days+DAY(@Second_Date)

                     break;

                    end

                    else

                    begin

                     SELECT @month=@month+1

                    end

                   end

                   ELSE

                   BEGIN

                    SELECT @month=@month+1

                   END      

                SET @first_month=@first_month+1

               END



            SET @first_year  = @first_year  + 1

            END



            select @month=@month+(@days/30)

            select @days=@days%30



            if(@days>0)

            begin

             SELECT @RESULT=CAST(@month AS VARCHAR)+' Month '+CAST(@days AS VARCHAR)+' Days '

            end

            else 

            begin

             SELECT @RESULT=CAST(@month AS VARCHAR)+' Month '

            end

        END



        ELSE

        BEGIN

           SELECT @RESULT='ERROR'

        END





    RETURN @RESULT 

END
SELECT dateadd(dd,number,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)) AS gun FROM master..spt_values
WHERE type = 'p'
AND year(dateadd(dd,number,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)))=year(DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))
CREATE FUNCTION ufFullMonthDif (@dStart DATE, @dEnd DATE)
RETURNS INT
AS
BEGIN
    DECLARE @dif INT,
            @dEnd2 DATE
    SET @dif = DATEDIFF(MONTH, @dStart, @dEnd)
    SET @dEnd2 = DATEADD (MONTH, @dif, @dStart)
    IF @dEnd2 > @dEnd
        SET @dif = @dif - 1
    RETURN @dif
END
GO

SELECT dbo.ufFullMonthDif ('2009-04-30', '2009-05-01')
SELECT dbo.ufFullMonthDif ('2009-04-30', '2009-05-29')
SELECT dbo.ufFullMonthDif ('2009-04-30', '2009-05-30')
SELECT dbo.ufFullMonthDif ('2009-04-16', '2009-05-15')
SELECT dbo.ufFullMonthDif ('2009-04-16', '2009-05-16')
SELECT dbo.ufFullMonthDif ('2009-04-16', '2009-06-16')
SELECT dbo.ufFullMonthDif ('2019-01-31', '2019-02-28')

위 기능을 일부 변경하는 것이 저에게 효과가 있었습니다.

CREATE FUNCTION [dbo].[Full Months Separation] (@DateA DATTIME, @DateB DATTIME ) BEGIN DELETE @Result INT로 반환

DECLARE @DateX DATETIME
DECLARE @DateY DATETIME

IF(@DateA < @DateB)
BEGIN
    SET @DateX = @DateA
    SET @DateY = @DateB
END
ELSE
BEGIN
    SET @DateX = @DateB
    SET @DateY = @DateA
END

SET @Result = (
                SELECT 
                CASE 
                    WHEN DATEPART(DAY, @DateX) > DATEPART(DAY, @DateY)
                    THEN DATEDIFF(MONTH, @DateX, @DateY) - iif(EOMONTH(@DateY) = @DateY, 0, 1)
                    ELSE DATEDIFF(MONTH, @DateX, @DateY)
                END
                )

RETURN @Result

끝.

Declare @FromDate datetime, @ToDate datetime, 
        @TotalMonth int ='2021-10-01', @TotalDay='2021-12-31' int, 
        @Month int = 0

   WHILE @ToDate > DATEADD(MONTH,@Month,@FromDate)
        BEGIN
            SET @Month = @Month +1
        END
    SET @TotalMonth = @Month -1
    SET @TotalDay = DATEDIFF(DAY, DATEADD(MONTH,@TotalMonth, @FromDate),@ToDate) +1
    IF(@TotalDay = DAY(EOMONTH(@ToDate)))
        BEGIN
            SET @TotalMonth = @TotalMonth +1 
            SET @TotalDay =0    
        END

Result @TotalMonth = 3, @TotalDay=0

PostGres만 사용하는 경우 --

SELECT (DATE_PART('year', '2012-01-01'::date) - DATE_PART('year', '2011-10-02'::date)) * 12 +
              (DATE_PART('month', '2012-01-01'::date) - DATE_PART('month', '2011-10-02'::date));

여기에 모든 코너 케이스를 만족시키지 못한 답변들이 많아서 수정을 시작했습니다.이 작업은 다음과 같습니다.

  • 01/05/2021 - 02/04/2021 = 0개월
  • 01/31/1800 - 02/28/1800 = 1개월
  • 09/01/2021 - 10/31/2021 = 2개월

저는 이것이 일반적으로 필요한 모든 사건을 처리한다고 생각합니다.

declare @dateX date = '01/1/2022'
declare @datey date = '02/28/2022'
-- select datediff(month, @dateX, @datey) --Here for comparison
SELECT
CASE 
    WHEN DATEPART(DAY, @DateX) = 1 and DATEPART(DAY, @DateY) = DATEPART(DAY, eomonth(@DateY))
    THEN DATEDIFF(MONTH, @DateX, @DateY) + 1
    WHEN DATEPART(DAY, @DateX) > DATEPART(DAY, @DateY) and DATEPART(DAY, @DateY) != DATEPART(DAY, eomonth(@DateY))
    THEN DATEDIFF(MONTH, @DateX, @DateY) - 1
    ELSE DATEDIFF(MONTH, @DateX, @DateY)
END

저는 질문이 구체적으로 "전체 달 간격"을 묻는 것과 주어진 예에서 각 날짜가 "해당 날짜의 시작 지점"으로 처리된다는 것에 주목하는 것이 중요하다고 생각합니다.일부 의견에 따르면 year-01-31에서 year-02-28은 0의 결과라고 하기 때문에 이 후자의 항목은 중요합니다.맞습니다. 1월의 1일 완료일과 2월의 27일 완료일(02-28은 그날의 시작이므로 완료되지 않음)은 0 "전체" 달입니다.

점을 염두에 두고 StartDate가 <= EndDate인 경우 다음과 같은 조건이 충족될 것으로 생각합니다.

      (DATEPART(YEAR, EndDate) - DATEPART(YEAR, StartDate)) * 12 
    + (DATEPART(MONTH, EndDate) - DATEPART(MONTH, StartDate))
    - CASE WHEN DATEPART(DAY,EndDate) < DATEPART(DAY,StartDate) THEN 1 ELSE 0 END

날짜가 임의의 순서일 가능성을 수용하기 위해 다음을 수행합니다.

, CASE WHEN StartDate <= EndDate THEN
      (DATEPART(YEAR, EndDate) - DATEPART(YEAR, StartDate)) * 12 
    + (DATEPART(MONTH, EndDate) - DATEPART(MONTH, StartDate))
    - CASE WHEN DATEPART(DAY,EndDate) < DATEPART(DAY,StartDate) THEN 1 ELSE 0 END
  ELSE
      (DATEPART(YEAR, StartDate) - DATEPART(YEAR, EndDate)) * 12 
    + (DATEPART(MONTH, StartDate) - DATEPART(MONTH, EndDate))
    - CASE WHEN DATEPART(DAY,StartDate) < DATEPART(DAY,EndDate) THEN 1 ELSE 0 END
  END                                          AS FullMnthsBtwn

이 샘플의 경우:

select 
    StartDate, EndDate
into mytable
from (
values
      (cast(getdate() as date),cast(getdate() as date)) -- both same date
    -- original
    ,('2009-04-16','2009-05-15') -- > 0 full month
    ,('2009-04-16','2009-05-16') -- > 1 full month
    ,('2009-04-16','2009-06-16') -- > 2 full months

    -- '1/31/2018' and endDate of '3/1/2018', I get a 0 – Eugene
    , ('2018-01-31','2018-03-01')

    -- some extras mentioned in comments, both of these should return 0 (in my opinion)
    ,('2009-01-31','2009-02-28')
    ,('2012-12-31','2013-02-28')

    ,('2022-05-15','2022-04-16') -- > 0 full month
    ,('2022-05-16','2022-04-16') -- > 1 full month
    ,('2021-06-16','2022-04-16') -- > 10 full months

    ) d (StartDate, EndDate)

문의

select
      StartDate
    , EndDate
    , CASE WHEN StartDate <= EndDate THEN
          (DATEPART(YEAR, EndDate) - DATEPART(YEAR, StartDate)) * 12 
        + (DATEPART(MONTH, EndDate) - DATEPART(MONTH, StartDate))
        - CASE WHEN DATEPART(DAY,EndDate) < DATEPART(DAY,StartDate) THEN 1 ELSE 0 END
      ELSE
          (DATEPART(YEAR, StartDate) - DATEPART(YEAR, EndDate)) * 12 
        + (DATEPART(MONTH, StartDate) - DATEPART(MONTH, EndDate))
        - CASE WHEN DATEPART(DAY,StartDate) < DATEPART(DAY,EndDate) THEN 1 ELSE 0 END
      END                                          AS FullMnthsBtwn
from mytable
order by 1

결과

+------------+------------+---------------+
| StartDate  |  EndDate   | FullMnthsBtwn |
+------------+------------+---------------+
| 2009-01-31 | 2009-02-28 |             0 |
| 2009-04-16 | 2009-05-15 |             0 |
| 2009-04-16 | 2009-05-16 |             1 |
| 2009-04-16 | 2009-06-16 |             2 |
| 2012-12-31 | 2013-02-28 |             1 |
| 2018-01-31 | 2018-03-01 |             1 |
| 2021-06-16 | 2022-04-16 |            10 |
| 2022-05-15 | 2022-04-16 |             0 |
| 2022-05-16 | 2022-04-16 |             1 |
| 2022-07-09 | 2022-07-09 |             0 |
+------------+------------+---------------+

여기에서 db<>fiddle 참조하십시오(다른 응답도 비교).

저는 다른 답변들로부터 아이디어를 얻었지만, 그 중 어느 것도 제가 원하는 것을 정확하게 주지 않았습니다.

문제는 제가 "한 달 사이"라고 생각하는 것으로 귀결되는데, 이는 다른 사람들도 또한 찾고 있는 것일 수 있습니다.

예를 들어, 2월 25일부터 3월 25일까지는 비록 28일이지만 저에게는 한 달이 될 것입니다.또한 3월 25일부터 4월 25일까지 한 달을 31일로 생각합니다.

또한 1월 31일부터 3월 2일까지는 30일간이지만 1개월과 2일로 생각하고 있습니다.

또한 한 달의 분수는 한 달의 길이와 몇 월의 분수를 선택할지에 따라 달라지기 때문에 약간 의미가 없습니다.

그래서, 그 점을 염두에 두고, 저는 이 기능을 고안해 낸 것입니다.10진수를 반환하고, 정수 부분은 월 수이고, 10진수 부분은 일 수이므로, 3.07의 반환 값은 3개월 7일을 의미합니다.

CREATE FUNCTION MonthsAndDaysBetween (@fromDt date, @toDt date)
RETURNS decimal(10,2)
AS
BEGIN
    DECLARE @d1 date, @d2 date, @numM int, @numD int, @trc varchar(10);

    IF(@fromDt < @toDt)
    BEGIN
        SET @d1 = @fromDt;
        SET @d2 = @toDt;
    END
    ELSE
    BEGIN
        SET @d1 = @toDt;
        SET @d2 = @fromDt;
    END

    IF DAY(@d1)>DAY(@d2)
        SET @numM = year(@d2)*12+month(@d2)-year(@d1)*12-month(@d1)-1;
    ELSE
        SET @numM = year(@d2)*12+month(@d2)-year(@d1)*12-month(@d1);

    IF YEAR(@d1) < YEAR(@d2) OR (YEAR(@d1) = YEAR(@d2) AND MONTH(@d1) < MONTH(@d2))
    BEGIN
        IF DAY(@d2) < DAY(@d1)
            SET @numD = DAY(@d2) + DAY(EOMONTH(DATEADD(month,-1,@d2))) - DAY(@d1);
        ELSE
            SET @numD = DAY(@d2)-DAY(@d1);
    END
    ELSE
        SET @numD = DAY(@d2)-DAY(@d1);

    RETURN @numM + ABS(@numD) / 100.0;
END

sql 서버에서 이 공식은 시간의 앞뒤로 이동하는 데 사용됩니다.

DATEDIFF(month,@startdate, @enddate) + iif(@startdate <=@enddate,IIF(DAY(@startdate) > DAY(@enddate),-1,0),IIF(DAY(@startdate) < DAY(@enddate),+1, 0)))
SELECT 12 * (YEAR(end_date) - YEAR(start_date)) +
    ((MONTH(end_date) - MONTH(start_date))) +
    SIGN(DAY(end_date) / DAY(start_date));

이것은 SQL SERVER 2000에서 잘 작동합니다.

시도:

trunc(Months_Between(date2, date1))

업데이트됨 지금은 그냥

SELECT DATEDIFF(MONTH, '2019-01-31', '2019-02-28')

SQL 서버가 정확한 결과(1)를 반환합니다.

인터넷을 검색해 보았습니다.그리고 제가 찾은 제안은 끝에 +1을 추가하는 것입니다.

다음과 같이 시도합니다.

Declare @Start DateTime
Declare @End DateTime

Set @Start = '11/1/07'
Set @End = '2/29/08'

Select DateDiff(Month, @Start, @End + 1)

언급URL : https://stackoverflow.com/questions/1106945/calculating-number-of-full-months-between-two-dates-in-sql