Naps: MySQL DB Abfrage

Hi,

ich habe diese Abfrage:

SELECT count(*) FROM user_log WHERE  userID = xxx

in diese geändert:

SELECT sessionID, count(*) FROM user_log WHERE  userID= xxx GROUP BYsessionID``

und bekomme nun wie gewünscht die Anzahl an Einträgen pro sessionID.

Ich habe eine weitere Abfrage mit der ich die Zeit zwischen dem ersten Eintrag und dem letzten Eintrag einer Session abfrage:

SELECT  
  
    (SELECT `timestamp` FROM `user_log` WHERE `sessionID` = ? AND `userID` = xxx ORDER BY `timestamp` DESC LIMIT 1)  
                        -  
    (SELECT `timestamp` FROM `user_log` WHERE `sessionID` = ? AND `userID` = xxx ORDER BY `timestamp` ASC LIMIT 1)

Kann ich das in einer Abfrage, genauso wie bei der anderen Abfrage, kombinieren damit ich die Differenz pro sessionID erhalte? Also, nicht nur auf eine sessionID bezogen, sondern auf alle?

MfG Naps

  1. Tach!

    Ich habe eine weitere Abfrage mit der ich die Zeit zwischen dem ersten Eintrag und dem letzten Eintrag einer Session abfrage:

    SELECT

    (SELECT timestamp FROM user_log WHERE sessionID = ? AND userID = xxx ORDER BY timestamp DESC LIMIT 1)
        (SELECT timestamp FROM user_log WHERE sessionID = ? AND userID = xxx ORDER BY timestamp ASC LIMIT 1)

    
    >   
    > Kann ich das in einer Abfrage, genauso wie bei der anderen Abfrage, kombinieren damit ich die Differenz pro sessionID erhalte? Also, nicht nur auf eine sessionID bezogen, sondern auf alle?  
      
    Correlated Subquery nennt sich das, was du suchst. In der äußeren Query fragst du alle Session-IDs ab und korreliert dazu in den Subquerys die beiden Werte. Allerdings solltest du das auch ganz ohne Subquery mit dem GROUP BY wie beim Zählen hinbekommen, dann aber MIN() und MAX() vom timestamp holen.  
      
      
    dedlfix.
    
    1. Correlated Subquery nennt sich das, was du suchst. In der äußeren Query fragst du alle Session-IDs ab und korreliert dazu in den Subquerys die beiden Werte. Allerdings solltest du das auch ganz ohne Subquery mit dem GROUP BY wie beim Zählen hinbekommen, dann aber MIN() und MAX() vom timestamp holen.

      OK danke.
      Habe ich das mit dieser Abfrage richtig verstanden, bzw. wo liegt hier der Fehler?

      SELECT DISTINCT a.`sessionID` FROM `user_log` a WHERE a.userID = xxx AND a.`sessionID` = ANY  
      (  
        
      SELECT ( MAX(b.timestamp) - MIN(b.timestamp) ) FROM `user_log` b WHERE a.sessionID = b.sessionID  
        
      )
      

      MfG Naps

      1. Tach!

        Correlated Subquery nennt sich das, was du suchst. In der äußeren Query fragst du alle Session-IDs ab und korreliert dazu in den Subquerys die beiden Werte. Allerdings solltest du das auch ganz ohne Subquery mit dem GROUP BY wie beim Zählen hinbekommen, dann aber MIN() und MAX() vom timestamp holen.
        Habe ich das mit dieser Abfrage richtig verstanden, bzw. wo liegt hier der Fehler?

        Nicht ganz. Der wichtigere Teil zur einfacheren Lösung war mein letzter Satz. Nimm deine GROUP-BY-Variante und ergänze sie um den Min/Max-Teil. Eine Correlated Subquery führt auch zum Ziel, ist aber in dem Fall nicht notwendig.

        SELECT DISTINCT a.sessionID FROM user\_log a WHERE a.userID = xxx AND a.sessionID = ANY

        Wenn man denkt, ein DISTINCT verwenden zu müssen, sollte man besser noch einmal auf die Query schauen, denn oft ist das ein Zeichen, dass man eine unnötig große und redundante Zwischenergebnismenge gebildet hat.

        ANY ist nur eine der Möglichkeiten, Ccorrelated Subquery zu erstellen, aber nicht die für deinen Fall nutzbringende. Es hätte ungefähr so aussehen müssen, wobei statt der einfachen Auflistung im äußeren SELECT auch eine Rechnung stehen könnte:

        SELECT a.x, (SELECT timestamp FROM tab2 b WHERE b.x = a.x ORDER BY ...) min, (SELECT ...) max FROM tab1 a

        dedlfix.

        1. Nicht ganz. Der wichtigere Teil zur einfacheren Lösung war mein letzter Satz. Nimm deine GROUP-BY-Variante und ergänze sie um den Min/Max-Teil. Eine Correlated Subquery führt auch zum Ziel, ist aber in dem Fall nicht notwendig.

          Ok, so denke ich passts jetzt ;)

          SELECT  a.sessionID, ( MAX(a.timestamp) - MIN(a.timestamp) ) as count FROM user_log a WHERE a.userID = xxx AND a.sessionID != '' GROUP BY a.sessionID

          Danke!
          MfG Naps

          1. Ok, so denke ich passts jetzt ;)

            SELECT  a.sessionID, ( MAX(a.timestamp) - MIN(a.timestamp) ) as count FROM user_log a WHERE a.userID = xxx AND a.sessionID != '' GROUP BY a.sessionID

            Nein, natürlich nicht. Denkfehler. Ich tüftel noch ;)

            1. Tach!

              Ok, so denke ich passts jetzt ;)
              SELECT  a.sessionID, ( MAX(a.timestamp) - MIN(a.timestamp) ) as count FROM user_log a WHERE a.userID = xxx AND a.sessionID != '' GROUP BY a.sessionID
              Nein, natürlich nicht. Denkfehler. Ich tüftel noch ;)

              Was klappt nicht? Was soll eigentlich bei der Timestamp-Differenz rauskommen? Wieso stehen in der Session-ID Leerstrings und nicht NULL, wenn selbige unbekannt oder nicht vorhanden ist?

              dedlfix.

              1. Was klappt nicht? Was soll eigentlich bei der Timestamp-Differenz rauskommen? Wieso stehen in der Session-ID Leerstrings und nicht NULL, wenn selbige unbekannt oder nicht vorhanden ist?

                Ich hätte gerne die "Online-Zeit". Zur zweiten Frage: Ich weiß es nicht.

                Ich habe die Abfrage jetzt so:

                SELECT a.sessionID,  
                  
                (SELECT timestamp FROM user_log b WHERE b.sessionID = a.sessionID ORDER BY timestamp ASC LIMIT 1) as min,  
                (SELECT timestamp FROM user_log b WHERE b.sessionID = a.sessionID ORDER BY timestamp DESC LIMIT 1) as max  
                FROM user_log a WHERE a.userID = xxx GROUP BY a.sessionID
                

                allerdings, dauert sie über 30 Sekunden, was nicht tragbar ist.

                MfG Naps

                1. Tach!

                  Was klappt nicht? Was soll eigentlich bei der Timestamp-Differenz rauskommen? Wieso stehen in der Session-ID Leerstrings und nicht NULL, wenn selbige unbekannt oder nicht vorhanden ist?

                  Ich hätte gerne die "Online-Zeit". Zur zweiten Frage: Ich weiß es nicht.

                  Die solltest du aber beantworten können, den du schreibst da ja was rein - oder auch nicht. Dann gibt es vielleicht einen Default-Wert im CREATE-TABLE-Statement und das Feld ist NOT NULL. Ich würde da NULL bevorzugen, wenn die Session-ID nicht bekannt ist. Wie auch immer, die Zeit in Sekunden solltest du aber bekommen, wenn es sich bei den Timestamps um Unix-Timestamps handelt. Bei DATETIME-Werten geht vermutlich kein Minus (oder bringt kein sinnvolles Ergebnis), da muss dann eine der Zeitdifferenz-Funktionen verwendet werden.

                  Ich habe die Abfrage jetzt so:

                  SELECT a.sessionID,

                  (SELECT timestamp FROM user_log b WHERE b.sessionID = a.sessionID ORDER BY timestamp ASC LIMIT 1) as min,
                  (SELECT timestamp FROM user_log b WHERE b.sessionID = a.sessionID ORDER BY timestamp DESC LIMIT 1) as max
                  FROM user_log a WHERE a.userID = xxx GROUP BY a.sessionID

                  
                  >   
                  > allerdings, dauert sie über 30 Sekunden, was nicht tragbar ist.  
                    
                  Fehlen vielleicht Indexe auf UserID und SessionID? Aber selbst wenn du das so mit den Subquerys haben möchtest, kannst du statt Sortieren und Limitierten Min und Max verwenden.  
                    
                    
                  dedlfix.
                  
                  1. Die solltest du aber beantworten können, den du schreibst da ja was rein - oder auch nicht. Dann gibt es vielleicht einen Default-Wert im CREATE-TABLE-Statement und das Feld ist NOT NULL. Ich würde da NULL bevorzugen, wenn die Session-ID nicht bekannt ist. Wie auch immer, die Zeit in Sekunden solltest du aber bekommen, wenn es sich bei den Timestamps um Unix-Timestamps handelt. Bei DATETIME-Werten geht vermutlich kein Minus (oder bringt kein sinnvolles Ergebnis), da muss dann eine der Zeitdifferenz-Funktionen verwendet werden.

                    So ist es jetzt korrekt:
                    SELECT  a.sessionID, ( TIMESTAMPDIFF(SECOND, MIN(a.timestamp) , MAX(a.timestamp)) ) as count FROM user_log a WHERE a.userID = xx AND a.sessionID != '' GROUP BY a.sessionID

                    Fehlen vielleicht Indexe auf UserID und SessionID? Aber selbst wenn du das so mit den Subquerys haben möchtest, kannst du statt Sortieren und Limitierten Min und Max verwenden.

                    Ja die fehlten ;) Jetzt rennts flüssig ;)

                    Danke!

                    MFG
                    Naps

  2. Ich nenne das Verfahren "Unterabfragen". die kann man ganz einfach in eine bestehende Abfrage einbauen:

    select (select FELD from Unterabfrage ) as FELD_VON_UNTERABFRAGE, FELD, NOCH_EIN_FELD from hauptabfrage

    Wichtig ist, dass nur ein Feld zurück gegeben wird. Das ist einfach und reicht für deine Zwecke.

    Gruß
    das neunte Renntier
    T-Rex