2010-07-20 7 views
5

Mam tabelę z sygnaturami czasowymi i chcę podzielić ten stół na godzinne interwały, zaczynając od teraz do tyłu o kilka godzin. Nie jestem w stanie uzyskać potrzebnych wyników z funkcją T-SQL DATEDIFF, ponieważ zlicza ona ile razy minutnik przechodzi 12 między dwiema datami - chcę, aby liczba razy minęła dłoń , gdzie jest teraz między znacznikiem czasu a teraz.T-SQL DateDiff - partycja wg "pełnych godzin" zamiast "razy minęły 00 od"

Czy istnieje prosty sposób, aby to zrobić w T-SQL?

Aktualizacja: W odpowiedzi na komentarze, oto kilka przykładowych danych, kwerendy obecnie używam i jestem coraz wyniki, jak również wyniki chcę.

dane próbki:

TimeStamp 
********* 
2010-07-20 11:00:00.000 
2010-07-20 10:44:00.000 
2010-07-20 10:14:00.000 
2010-07-20 11:00:00.000 
2010-07-20 11:40:00.000 
2010-07-20 10:16:00.000 
2010-07-20 13:00:00.000 
2010-07-20 12:58:00.000 

Aktualny zapytania:

SELECT TimeStamp, DATEDIFF(HOUR, TimeStamp, CURRENT_TIMESTAMP) AS Diff FROM ... 

Wyniki:

 TimeStamp     Diff 
    *********     **** 
    2010-07-20 11:00:00.000  2 
    2010-07-20 10:44:00.000  3 
    2010-07-20 10:14:00.000  3 
    2010-07-20 11:00:00.000  2 
    2010-07-20 11:40:00.000  2 
    2010-07-20 10:16:00.000  3 
    2010-07-20 13:00:00.000  0 
    2010-07-20 12:58:00.000  1

Co wolałbym mieć:

 -- The time is now, for the sake of the example, 13:40 

    TimeStamp     Diff 
    *********     **** 
    2010-07-20 11:00:00.000  3 -- +1 
    2010-07-20 10:44:00.000  3 
    2010-07-20 10:14:00.000  4 -- +1 
    2010-07-20 11:00:00.000  3 -- +1 
    2010-07-20 11:40:00.000  2 or 3 -- edge case, I don't really care which 
    2010-07-20 10:16:00.000  4 -- +1 
    2010-07-20 13:00:00.000  1 -- +1 
    2010-07-20 12:58:00.000  1

Oznaczyłem wyniki, które zmieniły się na +1. Także, ja naprawdę nie obchodzi, czy jest to 0 lub 1-indeksowane indeksowane, ale w zasadzie, jeśli jest teraz 13:40 Chcę przęseł czasowych, które się taką samą wartość będzie

 12:40-13:40 1 (or 0) 
    11:40-12:40 2 (or 1) 
    10:40-11:40 3 (or 2) 
    09:40-10:40 4 (or 3)
+0

Czy możesz wyjaśnić, że z danych wejściowych i wyjściowych z oczekiwanym zapytanie, które napisałeś? – shahkalpesh

+0

DATEDIFF w minutach, a następnie podział całkowity przez 60? –

Odpowiedz

7

Czy nie jesteś wystarczy użyć DATEDIFF(minute,.., a następnie podzielić wynik przez 60 i wziąć wartość całkowitą. na przykład

SELECT DATEDIFF(minute, '2010-07-20 06:00', GETDATE())/60 

Wierzę, że to będzie niejawnie oddanych jako int jako DateDiff zwraca int, daje całe godziny bez zaokrąglania.

Aby korzystać z dokładną kwerendę z zaktualizowanym postu:

SELECT TimeStamp, (DATEDIFF(minute, TimeStamp, CURRENT_TIMESTAMP) /60) AS Diff FROM ... 
+0

To nadal nie będzie dokładne. Właśnie zmieniłeś błąd z 59 minut na 59 sekund ... – ErikE

+0

@Emtucifor: Błąd 59 sekund jest znacznie lepszy - użyję go, by zdecydować, czy użytkownik powinien otrzymać powiadomienie, czy nie, i powinny osiągać najwyżej jedną na godzinę. Błąd 59 minut w tym przypadku jest katastrofalny - błąd 59 sekund jest całkiem dobry. Mogę nawet uzyskać błąd, który jest jeszcze mniejszy (<1 sekunda), wykonując to samo z sekundami, co Ben z minutami. –

+0

Okay, nie ma problemu. Lubię jednak moją wersję odejmowania dat, ponieważ jest jeszcze prostsza i jest tak dokładna, jak pozwala na to typ danych. :) – ErikE

0

Można grupa na to:

SELECT DateDiff(Hour, 0, GetDate() - TimeStamp) 

Jeśli chcesz znać czas Stanowi, calc go:

DateAdd(Hour, -DateDiff(Hour, 0, GetDate() - TimeStamp), GetDate()) 

Jeśli nie lubisz odejmowania dat, to nadal można to zrobić, ale staje się nieco trudniejsze. Zamiast po prostu strzelać w ciemności, zadałem pytanie, czy to prawda.

SELECT 
    TimeStamp, 
    Now = GetDate(), 
    HourDiff = DateDiff(Hour, 0, GetDate() - TimeStamp), 
    HourCalc = DateAdd(Hour, -DateDiff(Hour, 0, GetDate() - TimeStamp), GetDate()), 
    HourDiff2 = DateDiff(Hour, DateAdd(Millisecond, AdjustMs, TimeStamp), DateAdd(Millisecond, AdjustMs, GetDate())), 
    HourCalc2 = DateAdd(Hour, -DateDiff(Hour, DateAdd(Millisecond, AdjustMs, TimeStamp), DateAdd(Millisecond, AdjustMs, GetDate())), GetDate()) 
FROM 
    (
     SELECT DateAdd(Second, -3559, GetDate()) 
     UNION ALL SELECT DateAdd(Second, -3600, GetDate()) 
     UNION ALL SELECT DateAdd(Second, -3601, GetDate()) 
    ) x (TimeStamp) 
    CROSS JOIN (
     SELECT 3599997 - DateDiff(Millisecond, 0, DateAdd(Hour, -DateDiff(Hour, 0, GetDate()), GetDate())) 
    ) D (AdjustMs) 

Niestety, musiałem wykorzystać moją wiedzę o rozdzielczości datetime typu danych (1/300-te sekundy), a tym samym 3600000 - 3 = 3599997. Jeśli korekta milisekundę została obliczona na podstawie znacznika czasu zamiast GetDate () wtedy nie byłoby to potrzebne, ale byłoby dużo bałaganu, ponieważ duże wyrażenie wewnątrz wyprowadzonej tabeli D musiałoby zostać użyte dwukrotnie w głównym zapytaniu, zastępując AdjustMs.

Obliczenia są bardziej skomplikowane, niż mogłoby się wydawać konieczne, ponieważ nie można po prostu obliczyć milisekund różnicy między przypadkowymi datami lub pojawi się błąd przepełnienia. Jeśli znasz zakresy dat możliwe, możesz odejść od wykonywania bezpośrednich obliczeń w milisekundach z użyciem innej daty zakotwiczenia niż "19000101 00: 00: 00.000" (0 w powyższych wyrażeniach).

Na drugim myśli, można dostać tylko 24+ dni milisekund do podpisanego długa:

SELECT DateAdd(Millisecond, 2147483647, 0) = '1900-01-25 20:31:23.647' 
+0

Wydaje się, że starasz się uniknąć odejmowania dat - ale z twojego wpisu wynika, że ​​mogą istnieć dobre powody, by tego nie chcieć. Dlaczego nie chcę odejmować dat? –

+0

Cóż, nie jest to wymagane w tym przypadku z ** datetime **, ale w SQL Server 2008 nie można dodawać ani odejmować wartości typu danych ** data **. Mimo tego, że ** datetime ** działa teraz, może nie być na zawsze. C# .Net także zabrania tego (możesz tylko dodawać i odejmować przedziały czasowe z dat lub innych okresów), więc wszyscy powinniśmy myśleć o sposobach uniknięcia tego, jeśli chcemy pozostać na szczycie tych rzeczy na dłuższą metę. Niektóre dni odejmowania datetimes mogą być przestarzałe, a następnie usunięte jako funkcja! – ErikE

0

użyję

FLOOR(24 * CAST(CURRENT_TIMESTAMP-[TimeStamp] as float)) 

Przypadek Testowy

DECLARE @GetDate datetime 
set @GetDate = '2010-07-20 13:40:00.000'; 

WITH TestData As 
(
select CAST('2010-07-20 11:00:00.000' AS DATETIME) AS [TimeStamp] UNION ALL 
select '2010-07-20 10:44:00.000' UNION ALL  
select '2010-07-20 10:14:00.000' UNION ALL 
select '2010-07-20 11:00:00.000' UNION ALL 
select '2010-07-20 11:40:00.000' UNION ALL 
select '2010-07-20 10:16:00.000' UNION ALL 
select '2010-07-20 13:00:00.000' UNION ALL 
select '2010-07-20 12:58:00.000' 
) 

SELECT [TimeStamp], FLOOR(24 * CAST(@GetDate-[TimeStamp] as float)) AS Diff 
FROM TestData 

Wyniki

(Trzeba by dodać 1 w celu uzyskania dokładnych wyników zostanie zaksięgowana, ale mówisz, że nie przeszkadza około 0 lub 1 indeksowane)

TimeStamp    Diff 
----------------------- ---------------------- 
2010-07-20 11:00:00.000 2 
2010-07-20 10:44:00.000 2 
2010-07-20 10:14:00.000 3 
2010-07-20 11:00:00.000 2 
2010-07-20 11:40:00.000 2 
2010-07-20 10:16:00.000 3 
2010-07-20 13:00:00.000 0 
2010-07-20 12:58:00.000 0 
+0

Dlaczego "24 *"? Co mi daje 'CAST (@ GetDate- [TimeStamp] AS FLOAT)? –

+0

@ Tomas. 'CAST (@ GetDate- [TimeStamp] AS FLOAT)' jest różnicą liczby dni. na przykład 1,75 to różnica 1 dnia i 18 godzin. Zatem pomnożenie przez 24 daje różnicę liczby godzin. Używając 'Floor', zgrupuj wszystko w ciągu jednej godziny. –

+0

Martin, z mojego doświadczenia konwersja do float nie jest wiarygodna dla datetime. Studiowałem to uważnie w przeszłości. Datediff (Hour, 0, Current_TimeStamp - TimeStamp) robi tę samą sztuczkę. – ErikE

Powiązane problemy