it-swarm.com.de

T-SQL: Runden Sie auf das nächste 15-Minuten-Intervall

Was ist der beste Weg, um einen HH: MM-Wert auf das nächste 15-Minuten-Intervall zu runden? Ich verfolge keine Sekunden, so dass sie keine Rolle spielen.

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

und so weiter. Gibt es dafür eine elegante Methode ohne UDF- oder Case-Anweisungen?

EDIT: Hier ist die SQL, die ich verwende, um die obigen Werte zu erhalten, die ich abrunden möchte:

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

starttime und stoptime sind SQL datetimes.

42
Dzejms

Dies wurde hier beantwortet Wie man eine Zeit in T-SQL rundet und ich denke, es sollte für Sie funktionieren.

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)
26
u07ch

Ich verwende derzeit eine dateadd/datediff-Variante mit einem Nulldatum (0). Kein Casting erforderlich:

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

GETDATE () ist das, was Ihre Datumszeit ist.

Dies wird für Datumsangaben mindestens bis zum Jahr 5500 funktionieren, bevor das Datum aufgrund eines Überlaufs ausfällt. Wenn Sie jedoch versuchen, die zweite Genauigkeit zu verwenden, wird oben sofort versagen. 

Wenn Sie ein anderes festes Datum verwenden, z. B. '2009-01-01' oder das heutige Datum (Warnung, hässlicheres SQL), wird dies behoben. Ein zukünftiger Termin wird auch funktionieren. Solange es einen Zeitteil von 00:00:00 hat, können Sie eine andere Datumszeit darauf verwenden.

zum Beispiel: auf die nächsten 30 Sekunden aufrunden:

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

Ich weiß, dass dies ein alter Beitrag ist, wollte aber meine Antwort teilen. Dies baut auf der Antwort von @hbrowser auf. Hier ist was ich mir ausgedacht habe. Dies wird auf die nächsten 15 Minuten auf- oder abgerundet.

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

Wenn Sie diese Logik inline und nicht innerhalb einer benutzerdefinierten Funktion ausführen, sollten Sie bei großen Recordsets eine höhere Leistung erzielen. 

Sie können die Rundungsart ändern, indem Sie die ROUND-Funktion austauschen, um FLOOR oder CAST expr AS INT zu verwenden, um immer abzurunden, oder CEILING, um immer abzurunden.

Ihr individueller Anwendungsfall bestimmt, welchen Rundungsstil Sie verwenden müssen.

Mit dem folgenden Skript können Sie die Unterschiede der verschiedenen Rundungstechniken beobachten:

HINWEIS: Um die Ausgabe zu vereinfachen, wurde jedes Ergebnis in TIME (0) umgewandelt. Dies geschieht nur, um die Ausgabe für dieses bestimmte Beispiel zu vereinfachen.

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
 Zeit gerundete gegossene Bodendecke 
 00:00:00 00:00:00 00:00:00 00:00:00 00:00:00 
 00:05:00 00:00:00 00 : 00: 00 00:00:00 00:15:00 .__ 00:10:00 00:15:00 00:00:00 00:00:00 00:15:00 
 00:15:00 00:15:00 00:15:00 00:15:00 00:15:00 .__ 00:20:00 00:15:00 00:15:00 00:15:00 00:30:00 .__ 00: 25: 00 00:30:00 00:15:00 00:15:00 00:30:00 
 00:30:00 00:30:00 00:30:00 00:30:00 00 : 30: 00 .__ 00:35:00 00:30:00 00:30:00 00:30:00 00:45:00 .__ 00:40:00 00:45:00 00:30:00 00:30:00 00:45:00 .__ 00:45:00 00:45:00 00:45:00 00:45:00 00:45:00 .__ 00:50:00 00:45: 00 00:45:00 00:45:00 01:00:00 .__ 00:55:00 01:00:00 00:45:00 00:45:00 01:00:00 
 01:00 : 00 01:00:00 01:00:00 01:00:00 01:00:00 
 01:05:00 01:00:00 01:00:00 01:00:00 01:15:00 
16
Jamie Paolino

Sie können ein Datum wie folgt auf das nächste Viertel aufrunden:

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

Umwandlung von datetime in doppelte Präferenz, um Überläufe zu vermeiden, double = float (53). Multiplizieren Sie mit 24 * 4 die Anzahl der Viertel eines Tages. Runden Sie auf das nächste Vielfache von Viertel mit floor () und teilen Sie es dann durch 24 * 4, um zur normalen Zeit zurückzukehren.

6
Andomar

Versuchte Andomars Antwort und es gab Rundungen um 30 und 00 Uhr - also ein paar Änderungen und das funktioniert perfekt:

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

Dies wird die letzten 15 Minuten anzeigen, nicht das nächste, d. H. Es wird nicht vorwärts gemacht, was genau das ist, was ich brauchte.

4
Tazz602

Okay der einfachste Weg: 

wandeln Sie die Minuten durch Division durch 60 in eine Dezimalzahl um.

8/60 = 0.1333333333333333

mit 4 multiplizieren

0.1333333333333333 * 4   = 0.5333333333333333

Rund um das Produkt: 

Round(0.5333333333333333,0) = 1

teilen Sie die runde Zahl durch 4

1/4 = 0.25 = 15 minutes

wenn Sie die Minuten wünschen, multiplizieren Sie sie einfach mit 60

0.25*60 = 15

Gib einem Mann einen Fisch ....

1

Versuche dies:

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))
1
Charles Bretana

- Dies ist mein Lieblingsweg zur Rundenzeit

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)
1
Rhift
DECLARE @t time  ='00:51:00.000' 
DECLARE @m  int = DATEPART(MI,@t)%15

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

-- 2012
SELECT DATEADD(mi,IIF(@m >=8,[email protected],-1*@m),@t)
1
MichaelJ
create function RoundQuarterHour
(
    @dt datetime
)
returns datetime
as
begin
    declare @result datetime
    declare @mm int
    set @mm=datepart(minute,@dt)
    set @result = dateadd(minute,[email protected] + (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'
0
feihtthief

Block in 15 Minuten einstellen:

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
0
Damián Herrera

Dies wird auf die nächsten 15 Minuten gerundet. Sie können @ROUND in das Intervall Ihrer Wahl ändern.

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
0
Jaime Bennett
    DECLARE   @Date             DATETIME = GETDATE()

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

Die Zeitrundung in T-SQL ist tatsächlich sehr problematisch und oft ungenau.

Vor Jahren habe ich mich mit dem Runden von Zeit auf Code konzentriert, anstatt mit all dem zusätzlichen Hub-Bub, den man in T-SQL tun muss, um dies zu ermöglichen und genau zu sein. Rundungszeiten im Code sind einfacher und genauer.

Wenn Sie in T-SQL stecken und keinen unterstützenden Code haben oder keinen Zugriff auf diesen Code haben, folgen Sie den zuvor genannten Beispielen. Ansonsten empfehle ich demütig, Code die Arbeit erledigen zu lassen.

0
Boydski

wie wäre es mit diesem? (Variable zur besseren Lesbarkeit hinzugefügt)

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

Die Prämisse geht dahin, um herauszufinden, welches Inkrement Sie wollen, wie viel Prozent davon sind 60 Minuten ... dann ermitteln Sie die erforderliche Anzahl von Inkrementen, um dorthin zu gelangen es ist eine einfache Funktion, um das nächste Inkrement auf- oder abzurunden.

Einfache funktion: 

    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
0
Thomas Bright