mysql: query frage

Seite 1 von 1 - Forum: Coding Stuff auf overclockers.at

URL: https://www.overclockers.at/coding-stuff/mysql_query_frage_144521/page_1 - zur Vollversion wechseln!


kleinerChemiker schrieb am 22.06.2005 um 12:33

in einer tabelle sind u.a. folgende felder:
serial, name, account, zeit

dabei handelt es sich um die daten von charakteren eines rollenspiels. jeder char hat eine unique serial. auf einem account können mehrere char's liegen. jeden tag kommt für jeden char ein neuer eintrag hinzu.

nun suche ich alle chars, bei gegebenen account. allerdings will ich pro char nur eine zeile und zwar die, wo zeit am höchsten (->aktuellsten) ist. mit folgendem query bekomme ich fast das, was ich will. problem ist nur, daß es mir immer die zeile ausspuckt, wo die zeit am niedrigsten (also am ältesten) ist. folglich könnte ich 'zeit DESC' im ORDER BY weglassen, da es nichts bringt.

SELECT serial, name, account, zeit
FROM chars
WHERE account
LIKE '$account'
GROUP BY serial
ORDER BY zeit DESC , account, name

wie bekomme ich immer den aktuellsten eintrag? der aktuellste eintrag eines chars muß nicht zwangsläufig die zeit der letzten eintragung haben. denn wenn der char gelöscht wird, werden keine weiteren eintragungen mehr vorgenommen.

tia

MIK


watchout schrieb am 22.06.2005 um 15:14

Welche mysql-version?


kleinerChemiker schrieb am 22.06.2005 um 17:20

4.1.10-nt, also subqueries möglich. hab mir bezüglich eh schon gedanken gemacht, nur hab ich noch nie mit subqueries gearbeitet bzw. auch keine ahnung davon.

SELECT serial AS s, name, account, zeit
FROM chars
WHERE account
LIKE '$account'
AND zeit=(SELECT max(zeit) FROM chars WHERE serial=s GROUP BY serial)
GROUP BY serial
ORDER BY account, name

wobei die fett geschriebene 's' die gerade aktuelle serial der jeweiligen zeile ist.

tia

MIK


pong schrieb am 22.06.2005 um 17:34

Zitat von untested
SELECT serial, name, account, zeit
FROM chars
WHERE account
LIKE '$account'
GROUP BY serial
HAVING MAX(zeit)
ORDER BY zeit DESC , account, name

pong


kleinerChemiker schrieb am 22.06.2005 um 17:44

ist zwar gültig, liefert aber ein leeres ergebnis. wobei having lt. doku nicht optimiert wird.


Ringding schrieb am 22.06.2005 um 20:04

Das von pong schaut recht unsinnig aus, das von kleinerChemiker besser. Nur das group by im inneren select erscheint mir recht sinnfrei. Aber Achtung: es gibt dann immer große Augen, wenn es zwei Charaktere mit der gleichen Zeit gibt, dann kommen nämlich plötzlich mehrere Zeilen raus und nicht nur eine, wie man es erwarten könnte.


kleinerChemiker schrieb am 22.06.2005 um 20:10

zu einem zeitpunkt gibt es keine chars mit identen serials. also zu jedem zeitpunkt ist die serial unique. allerdings kommen die serials öfters vor, da sie bei jedem zeitpunkt einmal vorkommen können.

das group by im inneren ist, weil ich ja max() nur bei nem group by verwenden kann und auch nur 1 ergebnis haben darf. das problem bei dem von mir ist (m.e.) daß ich mich nicht auf die serial im äußeren beziehen kann. denn jede serial kann einen anderen letzten eintragszeitpunkt haben.


watchout schrieb am 22.06.2005 um 20:10

Zitat von kleinerChemiker
ist zwar gültig, liefert aber ein leeres ergebnis. wobei having lt. doku nicht optimiert wird.
naja, "HAVING MAX(zeit)" is irgendwie kompletter Fehlschuss ;)

Code: PHP
SELECT * FROM chars
  INNER JOIN (
    SELECT MAX(zeit) as maxzeit FROM chars
    GROUP BY serial) AS fake
  ON(chars.zeit=fake.maxzeit)
WHERE account LIKE '$account'
GROUP BY serial
ORDER BY zeit DESC , account, name
Das is jetzt aber nur ein Schuss ins Blaue, weil ich weder testdaten noch ein MySQL 4.1.x hab :D

Aber ich denke so sollts gehn... *schluck*


kleinerChemiker schrieb am 22.06.2005 um 20:26

ich bin begeistert :)
es scheint genau das auszuspucken, was ich möchte.
ich würd auch gerne so gut ins balue schießen können ;)
wobei ich eigentlich nicht verstehe, wie das eigentlich funzt, aber hauptsache es funzt *g*

edit: ha, jetzt hab ichs doch verstanden. aber soo hätt ich wohl nie gedacht.


watchout schrieb am 22.06.2005 um 20:43

Zitat von kleinerChemiker
ich bin begeistert :)
es scheint genau das auszuspucken, was ich möchte.
ich würd auch gerne so gut ins balue schießen können ;)
wobei ich eigentlich nicht verstehe, wie das eigentlich funzt, aber hauptsache es funzt *g*

edit: ha, jetzt hab ichs doch verstanden. aber soo hätt ich wohl nie gedacht.
omfg es geht wirklich :eek: :D

Hm, naja nach mehreren MySQL-K(r)ämpfen mit version 3.x wo's nichtmal Subselects gibt kennt man dann schon ein paar Umwege - bzw. irgendwann hat man die Denkreihenfolge raus - Was will ich und welche Daten brauch ich dazu - der Rest ergibt sich, ist aber sicher mit Übung verbunden ;)


kleinerChemiker schrieb am 22.06.2005 um 21:35

ja, es geht wirklich. einziger nachteil, der mir in kurzen tests auffiel: es schient ziemlich performance hungrig zu sein. was vielleicht aber auch daran liegt, daß der table knapp 50mb groß ist. oder hab ich index schlecht gewehlt? hab nen primary key über serial&zeit und einen index auf account.


watchout schrieb am 22.06.2005 um 21:53

hmm...

Ein zusätzlicher Index auf "zeit", sowie "serial" (einzeln) sollte was bringen. (Aus sicht des einen Queries hier könntest du den Primary Key müllen, aber ich weiss ja nicht was du sonst damit machst)

Aber ja, der Query is performancelastig weil er wahrscheinlich einen Temptable intern macht. Irgendwo in der Doku steht das, dass er einen macht wenn er Subselects oder auch Joins auf die gleiche Table macht. (is irgendwie Nachvollziehbar)

Zusätzlich beschleunigen kannst es sicher wennst ne zusätzliche Table machst in dem du pro Char immer nur einen Entry mit <serial,zeit> hast. Das is jedoch reine Geschwindigkeits-Optimierung. Sollte man anfangs mal ausser acht lassen.

PS: gewehlt


kleinerChemiker schrieb am 22.06.2005 um 22:09

jo, weiß eh wie man wählen schreibt ;) aber beim schnellen tippen sind die finger manchmal schneller als das hirn.

ich hab dann noch queries, in der art:
SELECT * FROM chars WHERE serial=xxx AND (zeit=aaa OR zeit=bbb ....)

ich sollte mir mal wirklich ein buch durchlesen, damit ich weiß wann ich welche indexe (oder sind das indizes?) verwende.


watchout schrieb am 22.06.2005 um 22:15

Zitat von kleinerChemiker
SELECT * FROM chars WHERE serial=xxx AND (zeit=aaa OR zeit=bbb ....)
statt (x=a or x=b or x=c or...) verwende in mysql besser x IN(a,b,c,...)
Das kann mysql besser optimieren - zahlt sich bereits bei EINEM or aus ;)
ja und dafür sollt der primary sinnvoll sein imo - also ist berechtigt wie ich dachte :)




overclockers.at v4.thecommunity
© all rights reserved by overclockers.at 2000-2026