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
'programing' 카테고리의 다른 글
innoDB/XtraDB에서 mariaDB 전체 텍스트 검색 (0) | 2023.06.26 |
---|---|
ggplot에서 면 순서 수정 (0) | 2023.06.26 |
기본 바인더가 요청되었지만 'org.springframework.cloud.stream.messaging에 사용할 수 있는 바인더가 없습니다.특성 채널로 직접 연결' (0) | 2023.06.21 |
MongoDB 집계 프레임워크에서 0으로 나눗셈 처리 방법 (0) | 2023.06.21 |
파이썬에서 반복기를 재설정할 수 있습니까? (0) | 2023.06.21 |