"We are back" « oc.at

mysql: query frage

kleinerChemiker 22.06.2005 - 12:33 702 13
Posts

kleinerChemiker

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4330
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

Legend
undead
Avatar
Registered: Nov 2000
Location: Off the grid.
Posts: 6845
Welche mysql-version?

kleinerChemiker

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4330
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

Addicted
Avatar
Registered: Oct 2001
Location: Wien (ned im Kra..
Posts: 414
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

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4330
ist zwar gültig, liefert aber ein leeres ergebnis. wobei having lt. doku nicht optimiert wird.

Ringding

Pilot
Avatar
Registered: Jan 2002
Location: Perchtoldsdorf/W..
Posts: 4300
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

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4330
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

Legend
undead
Avatar
Registered: Nov 2000
Location: Off the grid.
Posts: 6845
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

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4330
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

Legend
undead
Avatar
Registered: Nov 2000
Location: Off the grid.
Posts: 6845
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

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4330
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

Legend
undead
Avatar
Registered: Nov 2000
Location: Off the grid.
Posts: 6845
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

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4330
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

Legend
undead
Avatar
Registered: Nov 2000
Location: Off the grid.
Posts: 6845
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 :)
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz