2008-10-03 9 views
4

Ich habe eine Liste von Zeiten in einer Datenbankspalte (die Besuche einer Website darstellt).SQL-Abfrage für die kumulative Häufigkeit der Liste der Datumsangaben

Ich muss sie in Intervallen gruppieren und dann eine kumulative Häufigkeitstabelle dieser Daten erhalten.

Zum Beispiel könnte ich habe:

9:01 
9:04 
9:11 
9:13 
9:22 
9:24 
9:28 

und ich möchte, dass in

9:05 - 2 
9:15 - 4 
9:25 - 6 
9:30 - 7 

konvertieren Wie kann ich das tun? Kann ich das in SQL sogar leicht erreichen? Ich kann es sehr leicht in C machen

Antwort

1

Erstellen Sie eine Tabelle periods beschreibt die Perioden, die Sie den Tag in teilen möchten.

SELECT periods.name, count(time) 
    FROM periods, times 
WHERE period.start <= times.time 
    AND     times.time < period.end 
GROUP BY periods.name 
+0

Dies würde die kumulativen Summen nicht geben, die gefragt wurde, fiel die „period.start <= times.time“ Aussage würde dies erreichen, wie meine Antwort zeigte . – ManiacZX

+0

Wahr. Ich habe die Frage falsch gelesen. – ephemient

3

Ich möchte darauf hinweisen, dass auf die genannte „Absicht“ des Problems basiert, Analyse auf den Besucherverkehr zu tun - ich habe diese Aussage die Zählungen in Uniform Gruppen zusammenzufassen.

Andernfalls (wie in den "Beispiel" -Gruppen) würden die Zählungen während eines 5-Minuten-Intervalls mit Zählungen in einem 10-Minuten-Intervall verglichen werden - was keinen Sinn ergibt.

Sie müssen auf die "Absicht" der Benutzeranforderung, nicht das wörtliche "Lesen" von ihm grok. :-)

create table #myDates 
     (
     myDate  datetime 
     ); 
    go 

    insert into #myDates values ('10/02/2008 09:01:23'); 
    insert into #myDates values ('10/02/2008 09:03:23'); 
    insert into #myDates values ('10/02/2008 09:05:23'); 
    insert into #myDates values ('10/02/2008 09:07:23'); 
    insert into #myDates values ('10/02/2008 09:11:23'); 
    insert into #myDates values ('10/02/2008 09:14:23'); 
    insert into #myDates values ('10/02/2008 09:19:23'); 
    insert into #myDates values ('10/02/2008 09:21:23'); 
    insert into #myDates values ('10/02/2008 09:21:23'); 
    insert into #myDates values ('10/02/2008 09:21:23'); 
    insert into #myDates values ('10/02/2008 09:21:23'); 
    insert into #myDates values ('10/02/2008 09:21:23'); 
    insert into #myDates values ('10/02/2008 09:26:23'); 
    insert into #myDates values ('10/02/2008 09:27:23'); 
    insert into #myDates values ('10/02/2008 09:29:23'); 
    go 

    declare @interval int; 
    set @interval = 10; 

    select 
     convert(varchar(5), dateadd(minute,@interval - datepart(minute, myDate) % @interval, myDate), 108) timeGroup, 
     count(*) 
    from 
     #myDates 
    group by 
     convert(varchar(5), dateadd(minute,@interval - datepart(minute, myDate) % @interval, myDate), 108) 

retuns: 

timeGroup    
--------- ----------- 
09:10  4   
09:20  3   
09:30  8   
+0

nicht kumulativ ... – KristoferA

+0

Ja, diesen Teil verpasst. :-) Ron –

+0

... aber der Satz "Sie müssen zu der" Absicht "der Benutzeranforderung, nicht das wörtliche" Lesen "von ihr grok. ' fast verdient einen upvote ... :) – KristoferA

0

Dies nutzt nicht wenig SQL-Tricks (SQL Server 2005):

CREATE TABLE [dbo].[stackoverflow_165571](
    [visit] [datetime] NOT NULL 
) ON [PRIMARY] 
GO 

;WITH buckets AS (
    SELECT dateadd(mi, (1 + datediff(mi, 0, visit - 1 - dateadd(dd, 0, datediff(dd, 0, visit)))/5) * 5, 0) AS visit_bucket 
      ,COUNT(*) AS visit_count 
    FROM stackoverflow_165571 
    GROUP BY dateadd(mi, (1 + datediff(mi, 0, visit - 1 - dateadd(dd, 0, datediff(dd, 0, visit)))/5) * 5, 0) 
) 
SELECT LEFT(CONVERT(varchar, l.visit_bucket, 8), 5) + ' - ' + CONVERT(varchar, SUM(r.visit_count)) 
FROM buckets l 
LEFT JOIN buckets r 
    ON r.visit_bucket <= l.visit_bucket 
GROUP BY l.visit_bucket 
ORDER BY l.visit_bucket 

Beachten Sie, dass es alle mal am selben Tag legt, und übernimmt sie in einer Datetime-Spalte sind . Das einzige, was es nicht tut, ist, dass die führenden Nullen aus der Zeitdarstellung entfernt werden.

1

Erstellen Sie eine Tabelle, die angibt, in welchen Intervallen Sie Summen erhalten möchten, und verbinden Sie dann die beiden Tabellen miteinander.

wie:

time_entry.time_entry 
----------------------- 
2008-10-02 09:01:00.000 
2008-10-02 09:04:00.000 
2008-10-02 09:11:00.000 
2008-10-02 09:13:00.000 
2008-10-02 09:22:00.000 
2008-10-02 09:24:00.000 
2008-10-02 09:28:00.000 

time_interval.time_end 
----------------------- 
2008-10-02 09:05:00.000 
2008-10-02 09:15:00.000 
2008-10-02 09:25:00.000 
2008-10-02 09:30:00.000 

SELECT 
    ti.time_end, 
    COUNT(*) AS 'interval_total' 
FROM time_interval ti 
INNER JOIN time_entry te 
    ON te.time_entry < ti.time_end 
GROUP BY ti.time_end; 


time_end    interval_total 
----------------------- ------------- 
2008-10-02 09:05:00.000 2 
2008-10-02 09:15:00.000 4 
2008-10-02 09:25:00.000 6 
2008-10-02 09:30:00.000 7 

Wenn stattdessen kumulative Summen zu wollen Sie Summen in einem Bereich gesucht, dann Sie eine TIME_START Spalte auf der TIME_INTERVAL Tabelle hinzufügen und die Abfrage zu

SELECT 
    ti.time_end, 
    COUNT(*) AS 'interval_total' 
FROM time_interval ti 
INNER JOIN time_entry te 
    ON te.time_entry >= ti.time_start 
      AND te.time_entry < ti.time_end 
GROUP BY ti.time_end; 
8
create table accu_times (time_val datetime not null, constraint pk_accu_times primary key (time_val)); 
go 

insert into accu_times values ('9:01'); 
insert into accu_times values ('9:05'); 
insert into accu_times values ('9:11'); 
insert into accu_times values ('9:13'); 
insert into accu_times values ('9:22'); 
insert into accu_times values ('9:24'); 
insert into accu_times values ('9:28'); 
go 

select rounded_time, 
    (
    select count(*) 
    from accu_times as at2 
    where at2.time_val <= rt.rounded_time 
    ) as accu_count 
from (
select distinct 
    dateadd(minute, round((datepart(minute, at.time_val) + 2)*2, -1)/2, 
    dateadd(hour, datepart(hour, at.time_val), 0) 
) as rounded_time 
from accu_times as at 
) as rt 
go 

drop table accu_times 
ändern

Ergebnisse in:

rounded_time   accu_count 
----------------------- ----------- 
1900-01-01 09:05:00.000 2 
1900-01-01 09:15:00.000 4 
1900-01-01 09:25:00.000 6 
1900-01-01 09:30:00.000 7 
2

Oh, viel zu kompliziert all das Zeug.

Normalisieren auf Sekunden, teilen, indem Sie Ihre Eimer Intervall, gestutzt und remultiply:

select sec_to_time(floor(time_to_sec(d)/300)*300), count(*) 
from d 
group by sec_to_time(floor(time_to_sec(d)/300)*300) 

Mit Ron Savage Daten, ich

+----------+----------+ 
| i  | count(*) | 
+----------+----------+ 
| 09:00:00 |  1 | 
| 09:05:00 |  3 | 
| 09:10:00 |  1 | 
| 09:15:00 |  1 | 
| 09:20:00 |  6 | 
| 09:25:00 |  2 | 
| 09:30:00 |  1 | 
+----------+----------+ 

erhalten Sie wünschen kann ceil() oder rund verwenden () anstelle von Boden().

Update: für eine Tabelle erstellt mit

create table d (
    d datetime 
); 
+0

Ja, aber was ist mit den Perioden, die keine Einträge hatte? Wenn in einem bestimmten 5-Minuten-Zeitrahmen keine Einträge vorhanden sind, würde ich gerne eine 0 sehen. Wie können Sie das erreichen? – dubek

+0

Sie benötigen eine Tabelle mit den gewünschten Zeitintervallen über einen Tag. Links verbinden Sie es mit der Spalte sec_to_time oben. Sie erhalten die Anzahl mit coalesce (count (*), 0). Ich denke @ ManiacZX's Vorschlag macht das. – dland