Frage

Guten Tag alle.

Ich habe diese Umgebung: Auf einer MySQL -DB wird jedes Mal, wenn sich ein Benutzer auf einer Website anmeldet, eine neue Zeile mit seinem Namen und der Zeit, in der er sich anmeldet. Da das System gegenseitig exklusiv ist, wird es zu einem bestimmten Zeitpunkt nur einen Benutzer geben, und wenn ein neuer Benutzer ankommt, wird der eine angemeldete angemeldet.

Jetzt haben sie mir gebeten, die Gesamtzeit aller Benutzer im System zu berechnen. Im Grunde muss ich alle Zeitunterschiede zu einem Login und seiner nächsten zusammenfassen.

user  |       timestamp     |
------------------------------
alpha | 2013-01-19 03:14:07
beta  | 2013-01-20 11:24:04
alpha | 2013-01-21 02:11:37
alpha | 2013-01-21 03:10:31    <---- a user could login twice, it is normal
gamma | 2013-01-21 11:24:04
beta  | 2013-01-21 11:25:00

Ich möchte Ihre Meinung fragen, da es viele Anmeldungen gibt. Dies ist der beste Weg, um die gesamte protokollierte Zeit eines Benutzers zu berechnen? In diesem Beispiel wird "Gamma" eine Anmeldezeit von 56 Sekunden haben, und das letzte Anmeldung von Beta kann ignoriert werden, da es zum Zeitpunkt der Ausführung dieses Schecks online ist. "Beta" wird also nur einen Eintrag haben.

Gibt es eine Möglichkeit, es über Abfrage zu berechnen? Oder ist es besser, eine Spalte "Zeit online" hinzuzufügen und den Sistem jedes Mal berechnen zu lassen, wenn ein Benutzer abmeldet, wie viel Zeit online verbracht hat?

War es hilfreich?

Lösung

Dies erfordert eine Selbstjagd, wenn Sie es in MySQL tun sollen. Es ist ein Schmerz im Nacken, ein Selbstjoin zu machen, weil MySQL in der Rownum-Funktion keine eingebaute Funktion hat. Aber es ist immer noch machbar.

Zunächst müssen wir eine Unterabfrage erstellen, um eine virtuelle Tabelle zu erstellen, die simuliert ist SELECT rownum, user, timestamp FROM login was wir tun können. http://sqlfiddle.com/#!2/bf6ef/2/0

SELECT @a:=@a+1 AS rownum, user, timestamp
    FROM (
        SELECT user, timestamp
          FROM login
         ORDER BY timestamp
    ) C,
    (SELECT @a:=0) s

Als nächstes müssen wir ein Selbstjagd dieser virtuellen Tabelle zu einer Kopie von sich selbst machen. Was wir in diesem Ergebnissatz wollen, ist eine Liste aller aufeinanderfolgenden Zeilenpaare in der Tabelle. Diese Abfrage ist ein Haarball - sie bringt die strukturiert in Strukturierte Abfragesprache. Aber es funktioniert. Hier ist es: http://sqlfiddle.com/#!2/bf6ef/4/0

SELECT first.user AS fuser, 
       first.timestamp AS ftimestamp,
       second.user AS suser,
       second.timestamp as stimestamp,
       TIMESTAMPDIFF(SECOND, first.timestamp, second.timestamp) AS timeloggedin

  FROM (
       SELECT @a:=@a+1 AS rownum, user, timestamp
         FROM (
             SELECT user, timestamp
               FROM login
           ORDER BY timestamp
              ) C,
          (SELECT @a:=0) s
        ) AS first
  JOIN (
       SELECT @b:=@b+1 AS rownum, user, timestamp
         FROM (
             SELECT user, timestamp
               FROM login
           ORDER BY timestamp
              ) C,
          (SELECT @b:=0) s
        ) AS second ON first.rownum+1 = second.rownum

Der ganze Trick für den Vergleich aufeinanderfolgender Zeilen ist die

SELECT (virtual_table) AS first
  JOIN (virtual_table) AS second ON first.rownum+1 = second.rownum

Abfragemuster. Das Rownum+1 = Rownum -Ding versammelt Zeilen miteinander aufeinanderfolgenden Zahlen.

Als nächstes müssen wir das Ergebnis dieser Abfrage zusammenfassen, um die Gesamtzeit für jeden Benutzer angemeldet zu werden. Das wird so funktionieren:

  SELECT user, SUM(timeloggedin) AS timeloggedin
    FROM (
          /* the self-joined query */
         ) AS selfjoin
   GROUP BY user
   ORDER BY user

Das sieht so aus: http://sqlfiddle.com/#!2/bf6ef/5/0

Dies ist die ganze Abfrage zusammen.

SELECT user, SUM(timeloggedin) AS timeloggedin
  FROM (
      SELECT first.user AS user, 
             TIMESTAMPDIFF(SECOND, first.timestamp, second.timestamp) AS timeloggedin
        FROM (
             SELECT @a:=@a+1 AS rownum, user, timestamp
         FROM (
                   SELECT user, timestamp
                     FROM login
                 ORDER BY timestamp
                    ) C,
                (SELECT @a:=0) s
              ) AS first
        JOIN (
             SELECT @b:=@b+1 AS rownum, user, timestamp
               FROM (
                   SELECT user, timestamp
                     FROM login
                 ORDER BY timestamp
                    ) C,
                (SELECT @b:=0) s
              ) AS second ON first.rownum+1 = second.rownum
         ) AS selfjoin
   GROUP BY user
   ORDER BY user

Es ist nicht wirklich intuitiv für jemanden, der an prozedurale, algorithmische und nachdenkliche Nachdenken gewöhnt ist. So machen Sie diese Art von Vergleich von aufeinanderfolgender Reihenfolge in SQL.

Andere Tipps

Versuchen Sie es damit ... weniger oder mehr ist die Lösung Ihres Problems ...

    CREATE TABLE `matteo` (
      `user` varchar(20) DEFAULT NULL,
      `timestamp` int(11) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

    INSERT INTO matteo(user, `timestamp`) VALUES ('alpha', 7);
    INSERT INTO matteo(user, `timestamp`) VALUES ('beta', 9);
    INSERT INTO matteo(user, `timestamp`) VALUES ('alpha', 17);
    INSERT INTO matteo(user, `timestamp`) VALUES ('alpha', 27);
    INSERT INTO matteo(user, `timestamp`) VALUES ('gamma', 77);
    INSERT INTO matteo(user, `timestamp`) VALUES ('beta', 97);

    select a.*,b.*,b.`timestamp`-a.`timestamp` as delta
    from
    (SELECT @rownum := @rownum + 1 AS id,t.*
          FROM matteo t,(SELECT @rownum := 0) r) a
    join
    (SELECT @rownum2 := @rownum2 + 1 AS id,t.*
          FROM matteo t,(SELECT @rownum2 := 0) r) b 
    where a.id=b.id-1

:-) Bis Montag !!!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top