MySQL DB Abfrage
Naps
- datenbank
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 BY
sessionID``
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
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
FROMuser_log
WHEREsessionID
= ? ANDuserID
= xxx ORDER BYtimestamp
DESC LIMIT 1)
(SELECTtimestamp
FROMuser_log
WHEREsessionID
= ? ANDuserID
= xxx ORDER BYtimestamp
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.
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
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
FROMuser\_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.
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
Ok, so denke ich passts jetzt ;)
SELECT a.
sessionID, ( MAX(a.timestamp) - MIN(a.timestamp) ) as count FROM
user_loga WHERE a.userID = xxx AND a.
sessionID!= '' GROUP BY a.sessionID
Nein, natürlich nicht. Denkfehler. Ich tüftel noch ;)
Tach!
Ok, so denke ich passts jetzt ;)
SELECT a.
sessionID, ( MAX(a.timestamp) - MIN(a.timestamp) ) as count FROM
user_loga 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.
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
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.
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
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