2016-04-12 15 views
3

Ich habe eine Tabelle, die wie dieseSuche nach in einer Liste von Zeiten zwischen Zeit in

userid | eventid | description | date  | starttime | endtime 
    1  1   Event 1  2016-02-02  09:30:00 11:00:00 
    1  2   Event 2  2016-02-02  13:30:00 15:00:00 
    1  3   Event 3  2016-02-02  17:30:00 21:00:00 
    2  4   Event 4  2016-02-03  13:00:00 14:00:00 
    2  5   Event 5  2016-02-03  15:00:00 16:00:00 

Ich brauche zu finden sucht, was durch den Benutzer die Summe der Zeit zwischen den Ereignissen am selben Tag ist.

So:

userid | timeBetween 
    1   05:00:00 
    2   01:00:00 

Ich sollte auch davon ausgehen, dass es überlappende Zeiten zum Beispiel event1 sein kann beginnt um 11.00 Uhr endet 13:00 Uhr und event2 beginnt 12:00 Uhr und endet 14.00 Uhr vom selben Benutzer am selben Tag. Diese Fälle sind selten und ich glaube, dass 00:00 hier die richtige Antwort ist.

Ich löste ein ähnliches Problem, die Summe der Länge aller Ereignisse pro Tag zu finden.

SELECT *, 
SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(`endtime`,`starttime`)))) as sumtime 
FROM `events` 
group by userid, date 
order by sumtime desc 

Antwort

1

diese Beispieldaten Gegeben:

CREATE TABLE t 
    (`userid` int, `eventid` int, `description` varchar(7), `date` date, `starttime` time, `endtime` time) 
; 

INSERT INTO t 
    (`userid`, `eventid`, `description`, `date`, `starttime`, `endtime`) 
VALUES 
    (1, 1, 'Event 1', '2016-02-02', '09:30:00', '11:00:00'), 
    (1, 2, 'Event 2', '2016-02-02', '13:30:00', '15:00:00'), 
    (1, 3, 'Event 3', '2016-02-02', '17:30:00', '21:00:00'), 
    (2, 4, 'Event 4', '2016-02-03', '13:00:00', '14:00:00'), 
    (2, 5, 'Event 5', '2016-02-03', '15:00:00', '16:00:00') 
; 

diese Abfrage

SELECT userid, SEC_TO_TIME(SUM(TIME_TO_SEC(diff))) AS time_between 
FROM (

    SELECT 
    TIMEDIFF(starttime, COALESCE(IF(userid != @prev_userid, NULL, @prev_endtime), starttime)) AS diff, 
    @prev_endtime := endtime, 
    @prev_userid := userid AS userid 
    FROM 
    t 
    , (SELECT @prev_endtime := NULL, @prev_userid := NULL) var_init_subquery 
    ORDER BY userid 

) sq 
GROUP BY userid; 

kehrt

+--------+--------------+ 
| userid | time_between | 
+--------+--------------+ 
|  1 | 05:00:00  | 
|  2 | 01:00:00  | 
+--------+--------------+ 

Erläuterung:

In diesem Teil

, (SELECT @prev_endtime := NULL, @prev_userid := NULL) var_init_subquery 
ORDER BY userid 

wir unsere Variablen initialisieren. Die ORDER BY ist sehr wichtig, da es keine Reihenfolge in einer relationalen Datenbank gibt, wenn Sie sie nicht angeben. Es ist so wichtig, weil die SELECT-Klausel die Zeilen in dieser Reihenfolge verarbeitet. In der SELECT Klausel ist die Reihenfolge auch sehr wichtig. Hier

@prev_endtime := endtime, 
@prev_userid := userid AS userid 

wir ordnen den Variablen die Werte der aktuellen Zeile zu. Da es sich nach dieser Zeile geschieht

TIMEDIFF(starttime, COALESCE(IF(userid != @prev_userid, NULL, @prev_endtime), starttime)) AS diff, 

die Variablen immer noch die Werte der vorherigen Reihe in der Funktion timediff() halten. Daher müssen wir auch COALESCE() verwenden, da in der ersten Zeile und wenn sich die Benutzer-ID ändert, kein Wert für die Berechnung des Diffs vorhanden ist. Um einen Wert von 0 zu erhalten, tauscht COALESCE() den Wert NULL mit der Startzeit aus.

Der letzte Teil ist offensichtlich, einfach die Sekunden der "zwischen Zeiten" zu summieren.

0

Wenn Sie die TIMEDIFF der MIN nehmen (Startzeit) und MAX (endtime) für jeden Benutzer/Tag und dann die Summe der Ereignisse subtrahieren, wie zuvor berechnet, dies wird Ihnen die Zeiten dazwischen.

+0

Ich habe diese Methode ausprobiert und es funktioniert nicht richtig, vor allem, wenn es Überschneidungen gibt. – AMD

+0

Ah, ich habe die Überlappungen nicht bemerkt, obwohl es mathematisch gesehen korrekt wäre, da der Abstand zwischen 1pm und 12h -1 Stunde beträgt! Nicht sehr hilfreich in einer praktischen Umgebung. Sie müssten alle negativen Werte für diesen Tag subtrahieren (dh hinzufügen). – Mike

+1

Ja, aber ich glaube, das ist eine gute Antwort für alle, die nach einem einfachen Weg suchen, um so schnell wie möglich Ergebnisse zu erhalten. – AMD

1

Hier ist eine Art und Weise können Sie den timeBetween Wert in SECONDS

SELECT 
firsttable.userid, 
SEC_TO_TIME(SUM(TIME_TO_SEC(secondtable.starttime) - TIME_TO_SEC(firsttable.endtime))) timeBetween 
FROM 
(
     SELECT 
     *, 
     IF(@prev = userid, @rn1 := @rn1 + 1, @rn1 := 1) rank, 
     @prev := userid 
     FROM eventtable,(SELECT @prev := 0,@rn1 := 1) var 
     ORDER BY userid,starttime DESC 
) firsttable 
INNER JOIN 
(
     SELECT 
     *, 
     IF(@prev2 = userid, @rn2 := @rn2 + 1, @rn2 := 1) rank, 
     @prev2 := userid 
     FROM eventtable,(SELECT @prev2 := 0,@rn2 := 1) var 
     ORDER BY userid,endtime DESC 
) secondTable 

ON firsttable.userid = secondtable.userid AND firsttable.rank = secondtable.rank + 1 AND 
    firsttable.date = secondtable.date 
GROUP BY firsttable.userid; 

TEST erhalten:

Unable eine Geige hinzuzufügen.

Also hier sind Testdaten mit Schema:

DROP TABLE IF EXISTS `eventtable`; 
CREATE TABLE `eventtable` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `userid` int(11) NOT NULL, 
    `eventid` int(11) NOT NULL, 
    `description` varchar(100) CHARACTER SET utf8 NOT NULL, 
    `date` date NOT NULL, 
    `starttime` time NOT NULL, 
    `endtime` time NOT NULL, 
    PRIMARY KEY (`id`) 
) ; 
INSERT INTO `eventtable` VALUES ('1', '1', '1', 'Event 1', '2016-02-02', '09:30:00', '11:00:00'); 
INSERT INTO `eventtable` VALUES ('2', '1', '2', 'Event 2', '2016-02-02', '13:30:00', '15:00:00'); 
INSERT INTO `eventtable` VALUES ('3', '1', '3', 'Event 3', '2016-02-02', '17:30:00', '21:00:00'); 
INSERT INTO `eventtable` VALUES ('4', '2', '4', 'Event 4', '2016-02-03', '13:00:00', '14:00:00'); 
INSERT INTO `eventtable` VALUES ('5', '2', '5', 'Event 5', '2016-02-03', '15:00:00', '16:00:00'); 

Ergebnis:

die obige Abfrage auf den gegebenen Testdaten durchführen werden Sie eine Ausgabe wie unten erhalten:

userid timeBetween 
1   05:00:00 
2   01:00:00 

Hinweis: Für überlappende Ereignisse wird die obige Abfrage verwendet Ich gebe Ihnen einen negativen Wert von timeBetween.

Sie können die die SEC_TO_TIME... Linie durch folgende ersetzen:

SEC_TO_TIME(IF(SUM(TIME_TO_SEC(secondtable.starttime) - TIME_TO_SEC(firsttable.endtime)) < 0, 0,SUM(TIME_TO_SEC(secondtable.starttime) - TIME_TO_SEC(firsttable.endtime)))) timeBetween 
+0

Das ist komplizierter als nötig, und wenn Sie solche komplizierten Antworten nicht erklären, können Sie sich die Mühe ersparen. – fancyPants

+0

Es tut mir sehr leid, dass ich die Komplexität jetzt nicht beseitigen konnte. Später kann ich die Abfrage optimieren. Nur auf den funktionellen Teil konzentriert. Danke für Ihren Vorschlag. – 1000111

-1

versuchen, dies auf

select TIMEDIFF('start_time','end_time') from your table

Hoffnung diese eine Hilfe, die Sie

Verwandte Themen