prosource

T-SQL: 15분 간격으로 반올림

probook 2023. 7. 7. 19:06
반응형

T-SQL: 15분 간격으로 반올림

HH:MM 값을 가장 가까운 15분 간격으로 반올림하는 가장 좋은 방법은 무엇입니까?저는 초를 추적하지 않기 때문에 초는 상관없습니다.

00:08:00 becomes 00:15:00 
00:07:00 becomes 00:00:00 
01:59:00 becomes 02:00:00 

등등.이를 위한 우아하고 비 UDF 또는 사례 진술 방법이 있습니까?

편집: 위의 값을 반올림하기 위해 사용하는 SQL은 다음과 같습니다.

CONVERT(CHAR(8), DATEADD(n, SUM(DATEDIFF(n, starttime, stoptime)), 0), 108)

starttime그리고.stoptime SQL입니다.datetimes의

현재 날짜가 0인 dateadd/datediff 변형을 사용하고 있습니다.주조 불필요:

select dateadd(minute, datediff(minute,0,GETDATE()) / 15 * 15, 0)

GETDATE()는 날짜/시간을 나타냅니다.

이는 오버플로로 인해 날짜 차이가 실패하기 전 적어도 5500년까지의 날짜에 적용됩니다.그러나 두 번째 정확도를 사용하려고 하면 위의 항목은 바로 실패합니다.

'2009-01-01'과 같은 다른 고정 날짜 또는 오늘 날짜(경고, 더 보기 흉한 SQL)를 사용하면 문제가 해결됩니다.미래의 날짜도 가능할 것입니다.시간 부분이 00:00:00이면 다른 날짜 시간을 기준으로 할 수 있습니다.

예: 가장 가까운 30초로 반올림:

select dateadd(second, round(datediff(second, '2010-01-01', GETDATE()) / 30.0, 0) * 30, '2010-01-01');

저는 이것이 오래된 게시물이라는 것을 알지만 제 답변을 공유하고 싶었습니다.이는 @hbrowser 응답을 기반으로 합니다.이것이 제가 생각해 낸 것입니다.이 시간은 15분 이내로 반올림됩니다.

SELECT DATEADD(MINUTE, ROUND(DATEDIFF(MINUTE, 0, GETDATE()) / 15.0, 0) * 15, 0);

이 논리를 사용자 정의 함수 내부가 아닌 인라인으로 수행하면 큰 레코드 집합에서 성능이 향상됩니다.

반올림이 발생하는 방식을 변경할 수 있습니다.ROUND를 사용하는 FLOOR또는CAST expr AS INT항상 반올림하거나 사용합니다.CEILING항상 반올림합니다.

사용자의 개별 사용 사례에 따라 사용해야 할 라운딩 스타일이 결정됩니다.

다음 스크립트를 사용하여 다양한 반올림 기법에 의해 제공되는 차이를 관찰할 수 있습니다.

참고: 각 결과가 TIME(0)에 캐스팅된 출력을 단순화하기 위해 이 작업은 특정 예제의 출력을 단순화하기 위해 수행됩니다.

DECLARE @SequenceStart SmallDateTime = CAST(GETDATE() AS Date); 
DECLARE @SequenceEnd SmallDateTime = DateAdd(HOUR, 2, @SequenceStart); -- Recursive CTEs should always have an upper limit
DECLARE @SequenceIntMins INT = 5; -- increment by 5 to show the difference with rounding
WITH TimeSequence([Time]) as
(
    SELECT @SequenceStart as [Time]
    UNION ALL
    SELECT DateAdd(MINUTE, 5, [Time]) FROM TimeSequence 
    WHERE [Time] <= @SequenceEnd
)
    SELECT [Time] = Cast([Time] as TIME(0))
    , Rounded = CAST(DATEADD(MINUTE, ROUND(DATEDIFF(MINUTE, 0, [Time]) / 15.0, 0) * 15, 0) as TIME(0))
    , Casted = CAST(DATEADD(MINUTE, CAST(DATEDIFF(MINUTE, 0, [Time]) / 15.0 AS INT) * 15, 0) as TIME(0))
    , Floored = CAST(DATEADD(MINUTE, FLOOR(DATEDIFF(MINUTE, 0, [Time]) / 15.0) * 15, 0) as TIME(0))
    , Ceilinged = CAST(DATEADD(MINUTE, CEILING(DATEDIFF(MINUTE, 0, [Time]) / 15.0) * 15, 0) as TIME(0))
FROM TimeSequence OPTION ( MaxRecursion 1000);
-- MaxRecursion may be neccessary if you change the interval or end of the sequence
둥근 주물 바닥 천장 시간00:00:00    00:00:00    00:00:00    00:00:00    00:00:0000:05:00    00:00:00    00:00:00    00:00:00    00:15:0000:10:00    00:15:00    00:00:00    00:00:00    00:15:0000:15:00    00:15:00    00:15:00    00:15:00    00:15:0000:20:00    00:15:00    00:15:00    00:15:00    00:30:0000:25:00    00:30:00    00:15:00    00:15:00    00:30:0000:30:00    00:30:00    00:30:00    00:30:00    00:30:0000:35:00    00:30:00    00:30:00    00:30:00    00:45:0000:40:00    00:45:00    00:30:00    00:30:00    00:45:0000:45:00    00:45:00    00:45:00    00:45:00    00:45:0000:50:00    00:45:00    00:45:00    00:45:00    01:00:0000:55:00    01:00:00    00:45:00    00:45:00    01:00:0001:00:00    01:00:00    01:00:00    01:00:00    01:00:0001:05:00    01:00:00    01:00:00    01:00:00    01:15:00

이것은 T-SQL에서 시간을 반올림하는 방법에 대한 답변이며, 저는 이것이 당신에게 도움이 될 것이라고 생각합니다.

CREATE FUNCTION [dbo].[RoundTime] (@Time datetime, @RoundTo float) RETURNS datetime
AS
BEGIN
    DECLARE @RoundedTime smalldatetime, @Multiplier float

    SET @Multiplier = 24.0 / @RoundTo

    SET @RoundedTime= ROUND(CAST(CAST(CONVERT(varchar, @Time, 121) AS datetime) AS float) * @Multiplier, 0) / @Multiplier

    RETURN @RoundedTime
END

-- Usage    
SELECT dbo.RoundTime('13:15', 0.5)

다음과 같이 날짜를 가장 가까운 분기로 반올림할 수 있습니다.

cast(floor(cast(getdate() as float(53))*24*4)/(24*4) as datetime)

오버플로를 방지하기 위해 날짜를 두 배의 프레시젼으로 주조하는 시간, 두 배의 = 플로트(53).24*4를 곱하면 하루의 쿼터 수가 됩니다.바닥()을 사용하여 가장 가까운 쿼터 배수로 반올림한 다음 24*4로 나누면 정상 시간으로 다시 변환됩니다.

Andomar의 답변을 시도해보니 30과 00에서 반올림 문제가 있었습니다. 그래서 몇 가지 수정하면 완벽하게 작동합니다.

cast(round(floor(cast(getdate() as float(53))*24*4)/(24*4),5) as smalldatetime)

여기에는 가장 가까운 것이 아니라 마지막 15분 증분이 표시됩니다. 즉, 앞으로 진행되지 않습니다. 이것은 정확히 제가 필요로 했던 것입니다.

좋아요, 가장 쉬운 방법은:

분을 60으로 나누어 10진수로 변환합니다.

8/60 = 0.1333333333333333

4를 곱하다

0.1333333333333333 * 4   = 0.5333333333333333

제품 반올림:

Round(0.5333333333333333,0) = 1

반올림수를 4로 나누다

1/4 = 0.25 = 15 minutes

만약 당신이 회의록을 원한다면 그것에 60을 곱하세요.

0.25*60 = 15

사람에게 물고기를 주시오.

사용해 보십시오.

Declare @Dt DateTime 
Set @Dt = getDate()

Select DateAdd(minute, 
        15 * ((60 * Datepart(hour, @Dt) + 
        Datepart(Minute, @Dt)+ 
        Case When DatePart(second, @Dt) < 30 
        Then 7 Else 8 End) / 15),
    DateAdd(day, DateDiff(day, 0, @Dt), 0))
DECLARE @t time  ='00:51:00.000' 
DECLARE @m  int = DATEPART(MI,@t)%15

-- 2008
SELECT DATEADD(mi,CASE WHEN @m >=8 THEN 15-@m ELSE -1*@m END,@t)

-- 2012
SELECT DATEADD(mi,IIF(@m >=8,15-@m,-1*@m),@t)

--이것이 제가 가장 좋아하는 라운드 타임 방법입니다.

DECLARE @Time DATETIME = GETDATE()
       ,@RoundInterval INT = 30  --in minutes, needs to be a number that can be divided evenly into 60
       ,@RoundDirection INT = 2  --0 is down to the last interval, 1 is to the nearest interval, 2 is up to the next interval

SELECT  DATEADD(MINUTE,DATEDIFF(MINUTE,0,DATEADD(SECOND,30*@RoundDirection*@RoundInterval,@Time))/@RoundInterval*@RoundInterval,0)
create function RoundQuarterHour
(
    @dt datetime
)
returns datetime
as
begin
    declare @result datetime
    declare @mm int
    set @mm=datepart(minute,@dt)
    set @result = dateadd(minute,-@mm + (round(@mm/cast(15 as float),0)*15) , @dt )

    return @result
end
go


           select dbo.RoundQuarterHour('2009-may-5 20:00') , '00'
 union all select dbo.RoundQuarterHour('2009-may-5 20:01') , '01'
 union all select dbo.RoundQuarterHour('2009-may-5 20:07') , '07'
 union all select dbo.RoundQuarterHour('2009-may-5 20:08') , '08'
 union all select dbo.RoundQuarterHour('2009-may-5 20:22') , '22'
 union all select dbo.RoundQuarterHour('2009-may-5 20:23') , '23'
 union all select dbo.RoundQuarterHour('2009-may-5 20:37') , '37'
 union all select dbo.RoundQuarterHour('2009-may-5 20:38') , '38'
 union all select dbo.RoundQuarterHour('2009-may-5 20:52') , '52'
 union all select dbo.RoundQuarterHour('2009-may-5 20:53') , '53'
 union all select dbo.RoundQuarterHour('2009-may-5 20:59') , '59'

T-SQL의 시간 반올림은 실제로 매우 문제가 많고 부정확한 경우가 많습니다.

몇 년 전에 저는 모든 시간을 코드로 반올림했습니다. T-SQL에서 수행해야 할 추가 허브-버브를 사용하여 정확하게 수행했습니다.코드에서 반올림 시간은 더 쉽고 훨씬 정확합니다.

T-SQL에 갇혀 지원 코드가 없거나 해당 코드에 액세스할 수 없는 경우 앞서 언급한 예를 따르십시오.그렇지 않으면 코드가 작업을 수행하도록 하는 것이 좋습니다.

이것은 어떠세요?(가독성을 위해 추가됨)

create function dbo.FloorTimeToQuarters
(
 @dt as datetime
)
RETURNS datetime
as

BEGIN

 DECLARE @timeAsInt bigint
 SET @timeAsInt = ( cast( @dt as float ) * 96 )
 RETURN DateAdd( hour, @timeAsInt % 96, cast( @timeAsInt / 96 as datetime)  )

END

15분 내에 블록을 설정하려면:

CREATE FUNCTION RoundQuarterHour (
    @dt DATETIME
) RETURNS DATETIME

AS
BEGIN
    DECLARE @date DATETIME
    SET @date = CONVERT(varchar(16),@dt,121) --Sin segundos, ni milisegundos
    RETURN DATEADD(MINUTE,(DATEPART(MINUTE,@date) % 15)*-1, @date)
END

PRINT dbo.RoundQuarterHour('2011/01/01 18:00:07')  --Jan  1 2011  6:00PM
PRINT dbo.RoundQuarterHour('2011/01/01 18:01:07')  --Jan  1 2011  6:00PM
PRINT dbo.RoundQuarterHour('2011/01/01 18:13:07')  --Jan  1 2011  6:00PM
PRINT dbo.RoundQuarterHour('2011/01/01 18:14:07')  --Jan  1 2011  6:00PM
PRINT dbo.RoundQuarterHour('2011/01/01 18:15:07')  --Jan  1 2011  6:15PM
PRINT dbo.RoundQuarterHour('2011/01/01 18:16:07')  --Jan  1 2011  6:15PM

이것은 가장 가까운 15분으로 반올림됩니다.@ROUND를 원하는 간격으로 수정할 수 있습니다.

Declare @Dt DateTime = '2016-01-01 14:38:00' 
DECLARE @ROUND int = 15;
SELECT
CASE WHEN (DATEPART(MINUTE, @Dt) % @ROUND) * 60 + DATEPART(SECOND, @Dt) < (30 * @ROUND)
THEN DATEADD(minute, datediff(minute,0, @Dt) / @ROUND * @ROUND, 0) 
ELSE DATEADD(minute, (DATEDIFF(minute,0, @Dt) / @ROUND * @ROUND) + @ROUND, 0) 
END

전제는 당신이 원하는 증가량을 파악하는 것으로 요약됩니다. 60분의 비율로 계산하면...거기에 도달하는 데 필요한 증분 횟수를 계산합니다.INT 값(이 값은 나머지 값에서 잘라냅니다)을 취하면 위 또는 아래로 올림하여 가장 가까운 증분으로 내림할 수 있는 간단한 함수가 나타납니다.

간단한 기능:

    ALTER FUNCTION [dbo].[RoundOffDateTime]
(
    @IncDate    DATETIME,
    @Increment  INT
)
RETURNS SMALLDATETIME
AS
BEGIN

    DECLARE @IncrementPercent DECIMAL(2,2) = CAST(@Increment as decimal)/60
    DECLARE @IncMinutes REAL = ROUND(CAST(DATEPART(mi,@IncDate) as decimal)/CAST(@Increment as decimal),0)
    DECLARE @MinutesNeeded INT = CAST(@IncMinutes * @Increment as INT)

    RETURN CAST(DATEADD(mi,@MinutesNeeded,DATEADD(ss,-DATEPART(ss,@IncDate),DATEADD(mi,-DATEPART(mi,@IncDate),@IncDate))) as smalldatetime)

END
    DECLARE   @Date             DATETIME = GETDATE()

    SELECT    @Date
            , DATEADD(ms, 900000 - DATEDIFF(ms, CAST(@Date AS DATE), @Date) % 900000, @Date)

언급URL : https://stackoverflow.com/questions/830792/t-sql-round-to-nearest-15-minute-interval

반응형