MySQL
-
ich hab eine Frage wegen SQL/Mysql
folgendes Problem
Ich habe eine Tabelle, wo Projekte verwaltet werden.
Dazu gibt es eine zweite Tabelle wo die History Einträge der entsprechenden Projekte verwaltet werden
(und zwar alle die jemals geschrieben würden).
In der History Tabelle ist eine Spalte die mit einem FOREIGN KEY die Projekt ID enthält.
Nun möchte ich die zwei Tabellen miteinander (left join) verbinden. Allerdings will ich von
jedem Projekt nur den letzten Eintrag (die History Tabelle hat eine Spalte Datum).select * from project cp left join history ch on (cp.project_id=ch.Company_history_project_id)
Company_history_project_id ist der FOREIGN KEY.
kann ich das irgendwie mit "where" lösen?
-
So könnte es vielleicht gehen:
select * from project cp left join history ch on (cp.project_id=ch.Company_history_project_id) order by datum desc limit 0,1
ich wüsste noch ne andere Möglichkeit, aber die benötigt
subselects, die es ja in mysql nicht gibt.geht aber bestimmt auch noch schöner.. (hoffe ich *g*)
-
Tow-B.de schrieb:
So könnte es vielleicht gehen:
select * from project cp left join history ch on (cp.project_id=ch.Company_history_project_id) order by datum desc limit 0,1
ich habe vorhin auch mal eine Weile herumgetüftelt, bin aber daran gescheitert. Ich kann mir nicht vorstellen, dass dein Code so funktioniert, denn der gibt doch wohl nur eine einzige Zeile aus, oder?
Aber ich habe es sogar nichtmal hinbekommen nur aus der Historytabelle direkt für jede ID die Zeile mit dem neusten Datum auszulesen
-
select ch.* from project cp,history ch where cp.project_id=ch.Company_history_project_id order by datum desc limit 1
-
Also bei mir bewirkt auch hier das LIMIT 1, dass nur eine einzige Zeile ausgegeben wird und nicht eine pro Projekt-ID
-
Vielleicht noch ein "GROUP BY cp.project_id" dabei ?
Folgende Tabellen: Tabelle "projekte" id projektname 1 Ping 2 Pong Tabelle "history" id projekt_id tstamp 1 2 7823923 2 2 2147483647 3 1 3829382 4 2 72837132 MySQL-Query: SELECT projekte.id as id,projekte.projektname as name, MAX(history.tstamp) as tstamp FROM projekte LEFT JOIN history ON ( projekte.id = history.projekt_id ) GROUP BY projekte.id ORDER BY projekte.id ASC Liefert: id name tstamp 1 Ping 3829382 2 Pong 2147483647
-
Ich dachte er wollte nur eine Zeile. Hab ich dann falsch verstanden? LIMIT 1 liefert auch nur eine Zeile aus der Ergebnismenge.
-
@geeky
So würde meine Lösung auch aussehen. Nur dass ich auch projektname in den GROUP BY mit aufnehmen würde
-
Jo, wenn man aus der History-Tabelle nur das Datum benötigt geht das so - aber was macht man, wenn man auch noch die anderen Werte aus der History-Tabelle (von der Zeile mit dem neusten Datum) haben will?! Geht das überhapt
Oder müsste man dazu erst Datum und ID auslesen und dann nachher in weiteren Anfragen dazu die ganzen Datensätze holen
-
Ich glaube ich hab da etwas Verwirrung gestiftet:
Ich brauche von jedem Projekt den letzten History Eintrag, aber danke schon mal an alle fürs Helfen.Für Oracle weiß ich eine Lösung, die aber erst ab MYSQL 4.0 geht, da es dort erst "UNION" gibt.
-
Aja verstehe. Eine Umgehung mit einem SQL-Befehl der UNION gibts leider nicht. Du müsstest also die Einträge deiner aktuellen Projekttabelle und die Einträge deiner Historytabelle jeweils mit einem SQL-Befehl holen. Bei der UNION hast du ja eigentlich eh zwei SELECTS, die schon das tun müssten was du brauchst. Also einfach aufsplitten und zweimal eine Abfrage senden und die Ergebnismenge in ein gemeinsames Array z. B. speichern ;).
@flenders
Du kannst gleich alles rausholen. Allerdings musst du hald jedes einzelne Feld extra angeben und alle Felder die keine sog. Agregatfunktion (wie max(), min(), sum(), ...) haben, müssten beim GROUP BY auftauchen. Etwas umständlich also und bei vielen Feldern ist es wahrscheinlich besser, sich nur den Primärschlüssel zu holen und dann die restlichen Daten über extra Abfragen zu bekommen.
-
Reicht ein GROUP BY für die Projekt-ID nicht aus ?
-
@AJ: Irgendwie verstehe ich das nicht so ganz
Wie kann ich denn konkret aus der history für jede Projekt-ID jeweils den kompleten Datensatz mit dem neusten Datum holen (mit einem einzigen SELECT)
-
(Verfluchte Tab-Stops, da nochmal: http://www.geeky.de/stuff/mysql.txt)
Gehen wir mal von diesen beiden Tabellen aus:
Tabelle "projekte"
id projektname
1 Ping
2 PongTabelle "history"
id projekt_id tstamp
1 2 7823923
2 2 2147483647
3 1 3829382
4 2 72837132SELECT projekte.id as id,projekte.projektname as name, MAX(history.tstamp) as tstamp FROM projekte LEFT JOIN history ON ( projekte.id = history.projekt_id ) GROUP BY projekte.id ORDER BY projekte.id ASC
MySQL macht dann vermutlich folgendes:
Erstmal beide Tabellen anhand von "ON (projekte.id=history.projekt_id)" zu einer verbinden:Tabelle temporär ;D projekte.id projekte.projektname history.id history.projekt_id history.tstamp 1 Ping 3 1 3829382 2 Pong 1 2 7823923 2 Pong 2 2 2147483647 2 Pong 4 2 72837132
Nun soll MySQL mittels der MAX()-Funktion den größten Timestamp pro projekt.id raussuchen (denn danach sollen die Einträge
gruppiert werden ("GROUP BY projekte.id"), daher kommen jetzt nur noch 2 Zeilen übrig:Tabelle temporär2 ;D projekte.id projekte.projektname history.id history.projekt_id history.tstamp 1 Ping 3 1 3829382 2 Pong 2 2 2147483647
...und da nur projekte.id als 'id', projekte.projektname als 'name' und der größte Timestamp pro projekt.id als 'tstamp'
selektiert wurden, liefert MySQL letztendlich das:id name tstamp 1 Ping 3829382 2 Pong 2147483647
Wenn man noch mehr Felder aus der Zeile mit dem größten timestamp braucht, muss man sie nur beim select mit angeben.
Wenn man z.B. in der history-tabelle noch eine Spalte 'aktion' hat und die auch haben will muss nur noch ein
history.aktion as 'aktion' mit angegeben werden und MySQL liefert eine 'aktion'-Spalte mit aus...Keine Ahnung ob ich das so richtig verstanden hab, aber zumindest funzt die Query
-
geeky schrieb:
Wenn man z.B. in der history-tabelle noch eine Spalte 'aktion' hat und die auch haben will muss nur noch ein history.aktion as 'aktion' mit angegeben werden und MySQL liefert eine 'aktion'-Spalte mit aus...
Genau hier liegt mein Problem - bei mir wird dann eben nicht die zum Max-Datum gehörige aktion ausgegeben, sondern "zufällig" eine aus den ganzen aktionen dieser ID
-
http://www.mysqlfreaks.com/statements/27.php
...demnach scheint MAX() nicht das zu tun was es soll.
Welchen Datentyp hat denn deine Datum-Spalte ? (Wobei wenn MAX() mit dem Datentyp nicht umgehen kann dürfte MySQL nen Fehler melden oder ?!)
-
Den Zusammenhang verstehe ich jetzt nicht so gnaz
-
@flenders
Kannst du mal deinen SELECT zeigen, die Daten deiner Tabellen und was du als Ergebnis bekommst?
-
id date val1 val2 1 2003-01-01 valprim1 valprim2 1 2004-01-01 valprim3 valprim4 1 2004-05-06 valprim10 valprim20 2 2003-08-09 sdf sdfsdf
"SELECT * FROM history GROUP BY id" liefert folgendes:
id date val1 val2 1 2003-01-01 valprim1 valprim2 2 2003-08-09 sdf sdfsdf
"SELECT id, MAX( date ) , val1, val2 FROM history GROUP BY id" liefert jetzt zwar das richtige Datum, aber eben nicht die dazugehörigen val1 und val2 Werte, sondern die wie oben
-
Wie wärs mit:
SELECT id, max(datum), val1, val2 FROM history GROUP BY id, val1, val2
Nachtrag:
Gerade ist mir eingefallen, dass das so trotzdem nicht geht. Du hast recht flenders, du musst dir zuerst die id holen und kannst dir dann erst mit dieser die restlichen (korekten) Daten holen.