2011-08-22 18 views
13

Próbuję wygenerować tabelę z szeregiem dat w niej.SQL Server 2008 Generowanie serii dat daty

Mam określoną datę początkową i datę zakończenia (końcowa data jest końcem sekwencji), dodaję przedział czasu ~ (to może się różnić) do daty rozpoczęcia w sekundach, a to daje mi datę końcową czas.

Następna sekwencja używa wartości daty zakończenia jako wartości początkowej i dodaje do niej przedział czasu w sekundach. Aby zademonstrować wynik, potrzebuję. Czy istnieje szybki sposób stworzyć taką tablicę, inny niż przy użyciu dużo wkładki do komend ?, Jestem bardzo zakłopotany

StartTime    Endtime     Duration 
2011-07-20 11:00:33  2011-07-20 11:09:47  554 
2011-07-20 11:09:47  2011-07-20 11:19:01  554 

    declare @StartTime datetime = '2011-07-20 11:00:33', 
    @EndTime datetime = '2011-07-20 15:37:34' 
    @Interval int = 554 -- this can be changed. 

    insert into tmp_IRange 
    values('2011-07-20 11:00:33', DATEADD(SECONDS, @Duration, 2011-07-20 11:00:33)) 

ten staje się bardzo uciążliwe .. szczególnie gdy czas data zakończenia jest 2011-07-20 15:37:34 istnieją wiele sprawozdań wkładek aby :(

+2

Nie zademonstrowałeś swoich wyników. Czy możesz pokazać pierwsze trzy i ostatnie trzy wiersze, których naprawdę chcesz? –

+1

Należy pamiętać, że odpowiedzi oparte na rekurencyjnych CTE mają limit 32767 poziomów rekursji. (Zobacz dokumentację MAXRECURSION.) – HABO

+2

@ user92546 - Tak nie jest. 'MAXRECURSION 0' jest nieograniczona. –

Odpowiedz

4

to powinno Ci zacząć. można ją dostosować do konkretnych potrzeb. Jak napisano generuje wiersz dla każdej minuty przyrost zaczynając od bieżącej daty & czasu.

DECLARE @BaseDate DateTime = GETDATE(); 

WITH DateTable (DateValue) AS (
    SELECT @BaseDate DateValue 
    UNION ALL 
    SELECT DATEADD(Minute, 1, DateValue) DateValue 
    FROM DateTable 
) 
SELECT * 
FROM DateTable 
WHERE DateValue < DATEADD(Day, 1, GETDATE()) 
OPTION (MAXRECURSION 0); 
+0

Robi co 1 sekundę, prawda? – JNK

+0

@JNK: Tak, edytowano opis i przyrosty. W rzeczywistości zapytanie trwało dość długo! – Yuck

+0

Cóż, masz tylko jedną zmienną datetime, podczas gdy OP ma dwie zmienne datetime i interwał.Dlaczego w twoim rozwiązaniu nie ma nic o interwale (554 sekundy) i dacie końcowej (zakładasz, że jest to 1-minutowa przerwa w ciągu jednego dnia)? –

16

Użyj rekurencyjne CTE

declare @StartTime datetime = '2011-07-20 11:00:33', 
    @EndTime datetime = '2011-07-20 15:37:34', 
    @Interval int = 554 -- this can be changed. 

;WITH cSequence AS 
(
    SELECT 
     @StartTime AS StartRange, 
     DATEADD(SECOND, @Interval, @StartTime) AS EndRange 
    UNION ALL 
    SELECT 
     EndRange, 
     DATEADD(SECOND, @Interval, EndRange) 
    FROM cSequence 
    WHERE DATEADD(SECOND, @Interval, EndRange) < @EndTime 
) 
/* insert into tmp_IRange */ 
SELECT * FROM cSequence OPTION (MAXRECURSION 0); 
+0

Czy w tym zapytaniu jest używane przedział czasu, wydaje się, że w tym zapytaniu występuje niezadeklarowana zmienna Czas trwania. – jrara

+0

@jrara: dzięki, naprawiono – gbn

+0

Działa przysmak dzięki – mouse

5

Ten dadzą poszczególne zakresy ale ignoruje rzeczywisty czas zakończenia (ponieważ jest < @interval po ostatniej ważnej zakresu):

;WITH x AS 
(
    SELECT TOP (DATEDIFF(SECOND, @StartTime, @EndTime)/@Interval) 
     rn = ROW_NUMBER() OVER (ORDER BY [object_id]) 
    FROM sys.objects 
) 
-- INSERT INTO dbo.tmp_IRange 
SELECT DATEADD(SECOND, @Interval * (rn-1), @StartTime), 
    DATEADD(SECOND, @Interval * rn, @StartTime) 
FROM x; 
+0

* "Następna sekwencja używa czasu zakończenia jako wartości początkowej" *, co oznacza, że ​​czas rozpoczęcia nie jest stałą wartością. –

+0

Dzięki @Andriy, tęskniłem za tym; skasowano pierwszą odpowiedź. –

0

Nadzieja ta pomaga ...

declare @StartTime datetime = '2011-07-20 11:00:33', 
@EndTime datetime = '2011-07-20 11:00:33', 
@Interval int = 554, 

@LimitTime datetime = '2011-07-20 15:37:34' 

WHILE @EndTime < @LimitTime 
BEGIN 
SELECT @EndTime = DATEADD(S, @Interval, @StartTime) 

SELECT @StartTime, @EndTime 
--INSERT INTO tmp_IRange VALUES(@StartTime, @EndTime) 

SELECT @StartTime = @EndTime 

END 
0

spróbuj tego kodu:

create table #T (date_begin datetime, date_end datetime)  

declare @StartTime datetime = '2011-07-20 11:00:33', 
    @EndTime datetime = '2011-07-20 15:37:34', 
    @Interval int = 554 -- this can be changed. 

while DATEADD(ss,@Interval,@StartTime)<[email protected] 
begin 
    insert #T 
    select @StartTime, DATEADD(ss,@Interval,@StartTime) 

    set @StartTime = DATEADD(ss,@Interval,@StartTime) 
end 


select * from #T 
3

tu inny nierekursywnych rozwiązanie zestawu opartego na którym stosuje się stół system zwany master..spt_values:

DECLARE 
    @StartTime datetime = '2011-07-20 11:00:33', 
    @EndTime datetime = '2011-07-20 15:37:34', 
    @Interval int = 554; 
SELECT 
    StartTime = DATEADD(SECOND, (number - 1) * @Interval, @StartTime), 
    EndTime = DATEADD(SECOND, (number - 0) * @Interval, @StartTime), 
    Duration = @Interval 
FROM master..spt_values 
WHERE type = 'P' 
    AND number BETWEEN 1 AND DATEDIFF(SECOND, @StartTime, @Endtime)/@Interval 

UNION ALL 

SELECT 
    DATEADD(SECOND, -Duration, EndTime), 
    EndTime, 
    Duration 
FROM (
    SELECT 
    EndTime = @EndTime, 
    Duration = DATEDIFF(SECOND, @StartTime, @Endtime) % @Interval 
) s 
WHERE Duration > 0 

Pierwszy SELECT generuje zestaw rząd składał się z krótkich odstępach określonej długości, które mieszczą się w określonym zakresie. Jeśli to konieczne, drugie WYBIERANIE dodaje interwał pomiędzy końcem ostatniego przedziału czasu SELECT a określonym czasem zakończenia.

Podsekcja , która jest szczególnie używana tutaj (i może być używana w wielu podobnych przypadkach), zawiera listę liczb od 0 do 2047. Oznacza to, że nie będziesz w stanie użyć tego rozwiązania z tą tabelą jeśli początkowy interwał zostanie podzielony na więcej niż 2047 krótkich (er) przedziałów. Powinieneś wtedy pomyśleć o czymś w rodzaju własnego number table.

+0

+1 ale proszę nazwać to tabelą liczb lub liczb, a nie tabelą taryfikacyjną. Jest to tabela liczb, a nie tabela kwot. :-) –

+0

Nie ma problemu! Myślałem, że te dwa terminy były całkowicie zamienne. Chociaż przyznaję, nie mogę w pełni zrozumieć wszystkich subtelności znaczenia słowa * tally * (i wynika z tego, że powinienem być bardziej ostrożny w moich wcześniejszych zastosowaniach terminu * tabela tally *). Dziękuję bardzo za zawiadomienie! –

+1

Jeff Moden próbuje "wymyślić" ideę tabeli liczb (która nie pochodzi od niego), zmieniając jej nazwę. Tak więc dyskusje rozwijają się, gdy dwoje ludzi używa różnych terminów i może to być mylące. Tabela liczb * może * być użyta do sumowania, ale jest to bardzo specyficzny przypadek użycia, nawet jeśli jest to jeden z bardziej powszechnych przypadków. Tak czy inaczej, to jest po prostu moja opinia, całkowicie subiektywna, ale staram się zestresować proliferację terminu "stół do stołu", gdy myślę, że ludzie mogą słuchać. :-) –

Powiązane problemy