So gruppieren Sie die Zeit nach Stunden oder nach 10 Minuten


167

wie wenn ich es tue

SELECT [Date]
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY [Date]

Wie kann ich den Gruppenzeitraum angeben?

MS SQL 2008

2. Bearbeiten

Ich versuche

SELECT MIN([Date]) AS RecT, AVG(Value)
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY (DATEPART(MINUTE, [Date]) / 10)
  ORDER BY RecT

% 10 auf / 10 geändert. Ist es möglich, eine Datumsausgabe ohne Millisekunden durchzuführen?

Antworten:


213

endlich fertig mit

GROUP BY
DATEPART(YEAR, DT.[Date]),
DATEPART(MONTH, DT.[Date]),
DATEPART(DAY, DT.[Date]),
DATEPART(HOUR, DT.[Date]),
(DATEPART(MINUTE, DT.[Date]) / 10)

11
Ich habe es ROUND((DATEPART(MINUTE, DT.[Date]) / 5),0,1) * 5so gemacht , dass wenn ich mir die Daten
ansehe,

7
Jahr, Monat und Tag können vereinfacht werden DATE(DT.[Date]).

@Keelan Funktioniert bei mir nicht - CONVERT (Datum, DT. [Datum]) jedoch.
Dan Parsonson

datepart(hour, workingPolicy.workingHours)/2.0gibt 1.5während datepart(hour, '1900-01-01 09:00:30.000')/2.0gibt 4.5, ich verstehe nicht warum? Hinweis: workingPolicy.workingHours = 1900-01-01 09: 00: 30.000 . Bitte helfen Sie
affanBajwa

65

Ich bin super spät zur Party, aber dies erscheint in keiner der vorhandenen Antworten:

GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', date_column) / 10 * 10, '2000')
  • Die 10und MINUTEBegriffe können in eine beliebige Anzahl und geändert werdenDATEPART .
  • Es ist ein DATETIMEWert, was bedeutet:
    • Es funktioniert gut über lange Zeitintervalle. (Es gibt keine Kollision zwischen den Jahren.)
    • Wenn Sie es in die SELECTAnweisung aufnehmen, erhält Ihre Ausgabe eine Spalte mit hübscher Ausgabe, die auf der von Ihnen angegebenen Ebene abgeschnitten ist.
  • '2000'ist ein "Ankerdatum", um das SQL die Datumsberechnung ausführt. Jereonh hat unten festgestellt , dass beim Auftreten der0 letzten Daten nach Sekunden oder Millisekunden ein ganzzahliger Überlauf mit dem vorherigen Anker ( ) auftritt .
SELECT   DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', aa.[date]) / 10 * 10, '2000')
                                                               AS [date_truncated],
         COUNT(*) AS [records_in_interval],
         AVG(aa.[value]) AS [average_value]
FROM     [friib].[dbo].[archive_analog] AS aa
GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', aa.[date]) / 10 * 10, '2000')
ORDER BY [date_truncated]

Wenn Ihre Daten Spannweiten Jahrhunderte mit einem einzigen Anker Datum für Zweit- oder Millisekunden Gruppierung werden nach wie vor dem Überlauf auftreten. In diesem Fall können Sie jede Zeile bitten, den Binning-Vergleich mit der Mitternacht ihres eigenen Datums zu verankern:

  • Verwenden Sie DATEADD(DAY, DATEDIFF(DAY, 0, aa.[date]), 0)statt '2000'wo immer es oben erscheint. Ihre Anfrage ist völlig unlesbar, funktioniert aber.

  • Eine Alternative könnte CONVERT(DATETIME, CONVERT(DATE, aa.[date]))der Ersatz sein.

2 32 ≈ 4,29E + 9. Wenn dies der Fall DATEPARTist SECOND, erhalten Sie auf beiden Seiten 4,3 Milliarden Sekunden oder "Anker ± 136 Jahre". In ähnlicher Weise sind 2 32 Millisekunden ≈ 49,7 Tage.
Wenn Ihre Daten tatsächlich Jahrhunderte oder Jahrtausende umfassen und immer noch auf die Sekunde oder Millisekunde genau sind… herzlichen Glückwunsch! Was auch immer Sie tun, machen Sie weiter.


Wäre es möglich, dies ab einem bestimmten Startdatum zu tun?
Pylander

1
@ Pylander Sicher. Stellen Sie einfach eine whereKlausel vor die group by.
Michael - Wo ist Clay Shirky

2
Aha. Würde dies / 20 * 20also mit dem Sammeln von Daten für Intervalle von 20 Minuten identisch sein? Entschuldigung, ich habe gerade Probleme mit Mathe.
Einseitig

2
für SECOND als DATEPART erhalte ich eine Fehlermeldung ( The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.). Es scheint, dass MINUTE das kleinste Datum ist, das Sie mit diesem Ansatz verwenden können.
Jeroenh

1
@jeroenh, du bist richtig. Ich habe einen Abschnitt hinzugefügt, um darüber zu sprechen. tldr: Ändern Sie das 0in '2000'(Anführungszeichen sind wichtig!) und versuchen Sie es SECONDerneut.
Michael - Wo ist Clay Shirky?

17

In T-SQL können Sie:

SELECT [Date]
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY [Date], DATEPART(hh, [Date])

oder

durch Minutengebrauch DATEPART(mi, [Date])

oder

nach 10 Minuten verwenden DATEPART(mi, [Date]) / 10(wie Timothy vorgeschlagen)


GROUP BY [Date], DATEPART (hh, [Date]) ist ein Chaos, nicht?
cnd

1
@nCdy Sollte in Ordnung sein, sonst erhalten Sie eine Fehlermeldung "... ungültig in der Auswahlliste, da sie weder in einer Aggregatfunktion noch in der GROUP BY-Klausel enthalten ist"
tzup

Wie gruppieren Sie nach ganzem Datum und nach Stunden in derselben Zeit? Ich benutze nur Min Date.
cnd

Wenn Sie Min (Datum) verwenden, können Sie das Datum natürlich in der Gruppe nach herausnehmen.
Zup

3
Minuten geteilt durch 10 erzeugen eine Gruppierung in 10-Minuten-Intervallen, die ich benötige. Modulo 10 macht keinen Sinn.
Tar

12

Für ein Intervall von 10 Minuten würden Sie

GROUP BY (DATEPART(MINUTE, [Date]) / 10)

Wie schon von tzup und Pieter888 erwähnt ... nur ein Stundenintervall zu machen

GROUP BY DATEPART(HOUR, [Date])

2
aber hier gruppiere ich die Protokolle des Jahres 1980 mit den Protokollen des Jahres 2011: SI muss sich darum kümmern.
CND

Wäre% die richtige Mathematik? Würde das nicht 10 Gruppen schaffen? Zum Beispiel: 1% 10 = 9 2% 10 = 8 Es wäre auch nicht unbedingt die richtige chronologische Gruppierung. Ich denke, nur eine normale Kluft wäre richtig. Es sei denn,% ist keine Restteilung in SQL.
Steven

12
Minuten geteilt durch 10 erzeugen eine Gruppierung in 10-Minuten-Intervallen, die ich benötige. Modulo 10 macht keinen Sinn.
Tar

Einverstanden mit Tar. Die Gruppierung macht keinen Sinn.
Mike Murko

7

Sollte so etwas sein

select timeslot, count(*)  
from 
    (
    select datepart('hh', date) timeslot
    FROM [FRIIB].[dbo].[ArchiveAnalog]  
    ) 
group by timeslot

(Nicht 100% sicher über die Syntax - ich bin eher ein Oracle-Typ)

In Oracle:

SELECT timeslot, COUNT(*) 
FROM
(  
    SELECT to_char(l_time, 'YYYY-MM-DD hh24') timeslot 
    FROM
    (
        SELECT l_time FROM mytab  
    )  
) GROUP BY timeslot 

6

Die ursprüngliche Antwort des Autors funktioniert ziemlich gut. Um diese Idee zu erweitern, können Sie so etwas tun

group by datediff(minute, 0, [Date])/10

Dadurch können Sie über einen längeren Zeitraum als 60 Minuten gruppieren, z. B. 720, was einem halben Tag usw. entspricht.


1
Was wäre die MySQL-Abfrage für die oben genannten?
Biranchi

4

Für MySql:

GROUP BY
DATE(`your_date_field`),
HOUR(`your_date_field`),
FLOOR( MINUTE(`your_date_field`) / 10);

1

Meine Lösung besteht darin, mithilfe einer Funktion eine Tabelle mit den Datumsintervallen zu erstellen und diese Tabelle dann mit den Daten zu verknüpfen, die ich mithilfe des Datumsintervalls in der Tabelle gruppieren möchte. Das Datumsintervall kann dann bei der Darstellung der Daten einfach ausgewählt werden.

CREATE FUNCTION [dbo].[fn_MinuteIntervals]
    (
      @startDate SMALLDATETIME ,
      @endDate SMALLDATETIME ,
      @interval INT = 1
    )
RETURNS @returnDates TABLE
    (
      [date] SMALLDATETIME PRIMARY KEY NOT NULL
    )
AS
    BEGIN
        DECLARE @counter SMALLDATETIME
        SET @counter = @startDate
        WHILE @counter <= @endDate
            BEGIN
                INSERT INTO @returnDates VALUES ( @counter )
                SET @counter = DATEADD(n, @interval, @counter)
            END
        RETURN
    END

1
declare @interval tinyint
set @interval = 30
select dateadd(minute,(datediff(minute,0,[DateInsert])/@interval)*@interval,0), sum(Value_Transaction)
from Transactions
group by dateadd(minute,(datediff(minute,0,[DateInsert])/@interval)*@interval,0)

8
Willkommen bei stackoverflow. Sie müssen Ihre Antwort vollständig erklären und erklären, was dies zu den anderen 10 Antworten auf der Website beiträgt.
Simon.SA

0

Für SQL Server 2012 verwende ich, obwohl ich glaube, dass es in SQL Server 2008R2 funktionieren würde, den folgenden Ansatz, um die Zeit auf die Millisekunde zu reduzieren:

DATEADD(MILLISECOND, -DATEDIFF(MILLISECOND, CAST(time AS DATE), time) % @msPerSlice, time)

Dies funktioniert durch:

  • Ermitteln der Anzahl von Millisekunden zwischen einem festen Punkt und der Zielzeit:
    @ms = DATEDIFF(MILLISECOND, CAST(time AS DATE), time)
  • Nehmen Sie den Rest der Aufteilung dieser Millisekunden in Zeitscheiben:
    @rms = @ms % @msPerSlice
  • Hinzufügen des Negativs dieses Restes zur Zielzeit, um die Slice-Zeit zu erhalten:
    DATEADD(MILLISECOND, -@rms, time)

Da dies mit Mikrosekunden und kleineren Einheiten überläuft, müssten größere, feinere Datensätze leider einen weniger bequemen Fixpunkt verwenden.

Ich habe dies nicht rigoros bewertet und bin nicht in Big Data, daher kann Ihr Kilometerstand variieren, aber die Leistung war nicht merklich schlechter als bei den anderen Methoden, die an unseren Geräten und Datensätzen ausprobiert wurden, und die Auszahlung des Entwicklerkomforts für willkürliches Slicing macht es lohnenswert für uns.


0
select from_unixtime( 600 * ( unix_timestamp( [Date] ) % 600 ) ) AS RecT, avg(Value)
from [FRIIB].[dbo].[ArchiveAnalog]
group by RecT
order by RecT;

Ersetzen Sie die beiden 600 durch eine beliebige Anzahl von Sekunden, die Sie gruppieren möchten.

Wenn Sie dies häufig benötigen und sich die Tabelle nicht ändert, wie der Name Archive andeutet, ist es wahrscheinlich etwas schneller, das Datum (und die Uhrzeit) als Unixtime in der Tabelle zu konvertieren und zu speichern.


0

Ich weiß, dass ich mit diesem zu spät zur Show komme, aber ich habe diesen ziemlich einfachen Ansatz verwendet. Auf diese Weise erhalten Sie die 60-Minuten-Scheiben ohne Rundungsprobleme.

Select 
   CONCAT( 
            Format(endtime,'yyyy-MM-dd_HH:'),  
            LEFT(Format(endtime,'mm'),1),
            '0' 
          ) as [Time-Slice]

0
select dateadd(minute, datediff(minute, 0, Date), 0),
       sum(SnapShotValue)
FROM [FRIIB].[dbo].[ArchiveAnalog]
group by dateadd(minute, datediff(minute, 0, Date), 0)

1
Bitte geben Sie einige Erklärungen, wenn Sie eine Frage beantworten.
Shizzen83
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.