Mysql -> Having
Gerry
- datenbank
Hallo zusammen,
Ich habe eine Frage bezüglich MySQL.
In einer SQL Abfrage soll aus einer Gruppierung (GROUP BY CustomerId, Product) immer der neuste (IssueDate) Datensatz angezeigt werden.
Ich hab es so probiert:
"SELECT * FROM Products GROUP BY CustomerId, Product HAVING MAX(IssueDate)"
Funktioniert nicht... Habe da als Beispiel mehrere Datensätze kreiirt. Jeder ist ein Jahr höher. Trozdem wird der 2006 anstatt 2007 angezeigt. Aber nie 2005 oder 2004, was somit auch korrekt ist.
Wieso aber 2006 statt 2007, geht das mit dem HAVING anders? Oder ist es gar illegal?
Besten Dank & Gruss
vom Gerry
PS: Ich habe die INT Werte verglichen, und das 2007 ist tatsächlich > 2006 >2005 >2004... Somit, sollte HAVING funktionieren... :-S *confused*
Hello,
Ich hab es so probiert:
"SELECT * FROM Products GROUP BY CustomerId, Product HAVING MAX(IssueDate)"
keine Sorge, dein hiesiger Fehler unterläuft wohl allen, die GROUP BY auf MySQL lernen...
Eine SELECT Klausel in einer gruppierten Abfrage darf nur zwei Typen von Spalten enthalten:
Wieso aber 2006 statt 2007, geht das mit dem HAVING anders? Oder ist es gar illegal?
IMHO jein, also syntaktisch erlaubt aber sinnfrei. HAVING MAX(IssueDate) heißt nur in menschliche Sprache übersetzt "und hat das maximale IssueDate" - für die Datenbank entbehrt der Vergleich einer Grundlage, die will wissen welches MAX-Date du suchst. Entweder du lässt HAVING weg, selektierst MAX(IssueDate) mit, sortierst danach und verwendest LIMIT, oder du wendest ein weiteres SUBSELECT an
SELECT ..., MAX(IssueDate) m_i_dt
HAVING m_i_dt = (SELECT ... )
MfG
Rouven
Hallo Rouven,
[...] oder du wendest ein weiteres SUBSELECT an
als Ergänzung zu Deiner schönen Erklärung noch ein Link zu einem Archivposting
von mir, das korrelierte Subselects an einem Beispiel erläutert.
Freundliche Grüße
Vinzenz
yo,
du lässt HAVING weg, selektierst MAX(IssueDate) mit, sortierst danach und verwendest LIMIT
von dieser "lösung" ist immer abzuraten, es sei den im speziallfall, dass datensätze mit gleichen MAX(IssueDate) nicht alle angezeigt werden sollen, sondern nur einer von den mehreren möglichen. Aber auch dann würde ich aufgrund der besseren lesbarkeit eine andere lösung bevorzugen.
Ilja
Moin!
Ich habe eine Frage bezüglich MySQL.
Du bist in die wohlbekannte MySQL-Falle getappt, die beim Gruppieren bereitgehalten wird.
"SELECT * FROM Products GROUP BY CustomerId, Product HAVING MAX(IssueDate)"
SELECT * funktioniert zusammen mit GROUP BY nicht. MySQL liefert leider keinen Fehler, weil es diese Abfrage intern "optimiert", diese Optimierung ist allerdings nur in seltenen Fällen gültig.
Faustregel: Wann immer GROUP BY benutzt wird, dürfen in der Liste der selektierten Spalten nur auftauchen:
1. alle in GROUP BY auch aufgelisteten Spalten
2. alle anderen Spalten nur in Verbindung mit Aggregatfunktionen wie z.B. MAX, COUNT, AVG, SUM, etc...
Folgt also für dich: Du kannst mit deiner Abfrage derzeit nur CustomerID und Product ermitteln, weil nix anderes im GROUP BY steht. Logischerweise kannst du auch noch das Maximum der Spalte IssueDate in die Selektion aufnehmen. Aber mehr Infos kriegst du erstmal nicht.
Führe diese Abfrage mal durch in einem Admin-Tool (wie PHPMyAdmin). Dann siehst du die Liste.
Jetzt geht es ans Filtern unerwünschter Einträge. Mit WHERE filterst du, welche Datensätze in die Gruppierung eingehen sollen. Mit HAVING filterst du, welche gruppierten Ergebnisse ins Endergebnis einfließen sollen.
Funktioniert nicht... Habe da als Beispiel mehrere Datensätze kreiirt. Jeder ist ein Jahr höher. Trozdem wird der 2006 anstatt 2007 angezeigt. Aber nie 2005 oder 2004, was somit auch korrekt ist.
Wieso aber 2006 statt 2007, geht das mit dem HAVING anders? Oder ist es gar illegal?
Ohne Beispieldaten dürfte es schwierig werden, dein Problem nachzuvollziehen. Welche Bedeutung haben die Spalten? Was willst du ermitteln?
- Sven Rautenberg
Moin!
Moin!
Also ich habe nun 1. und 2. befolgt.
Ich kriege aber nicht den aktuellen, neusten Datensatz, sondern irgendeiner der per Zufall da in der GROUP BY ausselektiert wurde :-S (Keine Ahnung wie ich das beeinflussen soll.)
Wenn ich nun aber zusätzlich nebst den gebrauchten Felder ein MAX(IssueDate) as maxdate ausselektiere und dieses ausgebe, würde ich das KORREKTE Datum (Datensatz) dieser Gruppierung jeweils bekommen.
Wie kann ich also, dieses MAXDATE abfragen; Dass somit die Gruppierung GENAU den Datensatz nimmt, wo dieses MAXDATE dabei ist?!
Mit WHERE oder HAVING habe ich nun eine Zeit lang rumgespielt, hab aber das Ergebnis nicht so gekriegt wie ich wollte...
Gruss Gerry
Hier mein Query, das sich fast alle 5min ändert ;-)
SELECT MAX(IssueDate) AS maxda, tblCustomer.Id AS CustomerId, Product, Version FROM tblProduct LEFT JOIN tblCustomer ON Fk_CustomerId = tblCustomer.Id WHERE 1 GROUP BY CustomerId, Product, Version
Hab auch schon versucht HAVING(maxda) oder WHERE IssueDate=maxda und und... habe momentan echt Bahnhof...
Danke euch!
...Er sortiert nach der Id anstatt dem Datum innerhalb der Gruppe. Dies soll geändert werden... Innerhalb der Gruppe, dies kann man mit WHERE machen, soweit ich verstanden habe.
Kann mir dazu bitte jemand ein solches WHERE IssueDate=(Select MAX(IssueDate) beispiel geben.
Ich kriegs nicht hin :(
Danke
Hallo Gerry,
Ich kriege aber nicht den aktuellen, neusten Datensatz, sondern irgendeiner der per Zufall da in der GROUP BY ausselektiert wurde :-S (Keine Ahnung wie ich das beeinflussen soll.)
Gar nicht, das kannst Du nicht beeinflussen. Das Ergebnis ist zufällig.
Jedes andere DBMS (Datenbankmanagementsystem) als MySQL, das ich kenne,
gibt Dir sowieso kein Ergebnis, sondern eine Fehlermeldung zurück.
Wie kann ich also, dieses MAXDATE abfragen; Dass somit die Gruppierung GENAU den Datensatz nimmt, wo dieses MAXDATE dabei ist?!
Mit einem korrelierten Subselect.
SELECT MAX(IssueDate) AS maxda, tblCustomer.Id AS CustomerId, Product, Version FROM tblProduct LEFT JOIN tblCustomer ON Fk_CustomerId = tblCustomer.Id WHERE 1 GROUP BY CustomerId, Product, Version
Möchtest Du also das letzte Ausgabedatum je Produkt und Kunde haben?
SELECT -- Nimm
p.IssueDate, -- das Ausgabedatum
c.Id AS CustomerId, -- die KundenID
p.Product, -- das Produkt
p.Version, -- die Version
FROM tblProduct p -- aus der Tabelle Produkte
/*
Wenn Du eh' nach Kunden gruppierst, warum nimmst Du dann einen
LEFT JOIN. Ich würde eher einen INNER JOIN erwarten.
Oder interessiert dich auch die letzte Ausgabe eines Produkts,
zu dem _kein_ Kunde eingetragen wurde?
*/
LEFT JOIN tblCustomer c -- und der Tabelle Kunden
ON p.Fk_CustomerId = c.Id -- die über diese beiden Spalten verknüpft sind
WHERE p.IssueDate = ( -- wobei jeweils nur das
WHERE zeit = (
SELECT MAX(p2.IssueDate) -- das neueste Datum
FROM tblProduct p2
WHERE p.Product = p2.Product -- je Produkt
AND p.Fk_CustomerId = p2.Fk_CustomerId -- und Kunde interessiert.
)
ganz analog zu meinem bereits verlinkten Beispiel im Archiv.
Freundliche Grüße
Vinzenz
Hallo Gerry,
Tach auch :-)
Möchtest Du also das letzte Ausgabedatum je Produkt und Kunde haben?
Jupp...
Hey, ich möchte dir mal fett Danke sagen für dein Beispiel!!! Es läuft genau so wie es sollte. Ich habe auch noch die Joins ausgewechselt, weil du recht hast ;-)
Besten Dank für deine Super Hilfe & Gruss
Gerry