sql: "having klausel" ersetzen

Joined
Feb 2, 2007
Messages
4,344
Points
270
mit was könnte ich die having-klausel möglichst einfach ersetzen?

Code:
SELECT DISTINCT personal.personalnr, personal.nachname, personal.vorname, personal.kostenst AS KS_Personal,  personal.eintritt1, personal.persstatus, auftrag.auftragnr, auftrag.kostenst AS KS_Auftrag, auftrag.vonDatum AS vonDatum
FROM (personal INNER JOIN einsPers ON personal.personalNR=einsPers.personalNr) INNER JOIN auftrag ON auftrag.auftragNr=einsPers.auftragNr  
WHERE (personal.persstatus = 2 OR personal.persstatus = 7)  AND auftrag.auftstatus= 2 
GROUP BY personal.personalnr
HAVING MAX(vonDatum) 				
ORDER BY personal.nachname ASC

zur Erklräung:
ja, ich weiss, hinter "group by", müssten eigentlich sämtliche spalten stehen, welche nicht in der having-klausel stehen, oder?
aber auch wenn ich das mache, klappts nicht. genauer: er sagt mir, dass er having gar nicht kennt :?
nun dachte ich, kk, schmeiss mal alles raus, was zum einsatz von having nciht nötig ist. aber slbst dann sagt er mir er kenne es nicht.
es handelt sich hier übrigens um einen kleinen rudmentären editor, mit dem man abfragen an ein personalwirtschaftssystem stellen kann. ist es vielleicht so, dass der dialekt des systems having nicht beinhaltet? wie könnte ich das umgehen? da man dort auch einzelne prozeduren einhacken kann, würde ich notfalls auch damit arbeiten :)
ahjo, worum gehts in der abfrage eigentlich?
Ich will die aktuellsten Einsätze (einsPers) eines jeden Mitarbeiters (personal) zu Papier brinegn. Dazu möchte ich noch wissen, in welchem Auftrag (auftrag) diese stattfinden.

Schon mal vielen Dank für Eure Tipps :) Falls Ihr mehr Infos braucht, np!
 
Im Internet habe ich das gefunden,

Es ist möglich, durch umformulierung die having−Klausel zu ersetzen, ja.
Die Projektionen der eigentlichen Anfrage ggf. um Aggregationen aus der
having−Klausel erweitern, das Ganze in eine Unteranfrage packen, die
Selektionskriterien aus dem "having" in der äußeren Anfrage als normale
Selektionen unterbringen und ggf. durch Projektion in der äußeren
Anfrage die in der Unteranfrage ergänzten Werte wieder entfernen.
Ob und wie sich das auf die Performance auswirkt, hängt wohl davon ab,
wie intelligent der Optimierer der Datenbank ist.

kp obs dir hilft.
 
joa, sowas habe ich auch schon probiert:

Code:
SELECT DISTINCT personal.personalnr, personal.nachname, personal.vorname, personal.kostenst AS KS_Personal,  personal.eintritt1, personal.persstatus, auftrag.auftragnr, auftrag.kostenst AS KS_Auftrag, auftrag.vonDatum
FROM (personal AS perso INNER JOIN einsPers AS aPlan ON perso.personalNR=aPlan.personalNr) INNER JOIN auftrag AS au ON au.auftragNr=einsPers.auftragNr  
WHERE (personal.persstatus = 2 OR personal.persstatus = 7)  AND auftrag.auftstatus= 2 AND 
 	[COLOR="Red"]auftrag.vonDatum = (SELECT MAX(auftrag.vonDatum)
				FROM auftrag)[/COLOR]
ORDER BY personal.nachname ASC
nur bewirkt es bei mir (habe ich was falsch gemacht?), dass nur noch 1 einziger datensatz ausgespuckt wird - nämlich der aktuellste :(
ich will aber wie gesagt den aktuellsten jeweils zu jedem mitarbeiter...
@edit: wobei dein zitat schon recht schwer verständlich formuliert ist und ich mir gar nicht sicher bin, ob ichs überhaupt 100% verstanden habe...
 
Vorab, die Angaben sind ohen Gewähr da SQL schon bissel her ist bei mir.

Also Group müsste schon gehen.
Bei Having musst du glaub ich noch ein Ausdruck anfügen wie MAX (vonDatum) < Wert, weiß aber nicht ob man das auf Datumsangaben beziehen kann und was du damit ausdrücken möchtest.
Ich mach mal ein Bsp.:
SELECT abteilung, MAX(Gehalt) as "Höchstes Gehalt"
FROM angetsellten
GROUP BY abteilung
HAVING MAX(Gehalt) < 10000;

Damit wird erst das maximale Gehalt jeder Abteilung ermittelt und hinterher nur die angezeigt deren Gehalt nicht 10000 überschreitet.

Edit: Jo nat. wird nur der aktuellste Wert ermittelt denn das bezweckt der MAX Ausdruck ja das nur der höchste wert zurückgegeben wird der Tabelle.
 
Last edited:
hm, also wie gesagt, having steht nicht zur verfügung. syntax/semantik-mäßig habe ich da nix falsch gemacht. der abfrage-editor kennt having einfach nicht.
ich habe jetzt aber schon die richtige ergebnismenge rausbekommen :)
von daher ändert sich a bisserl die fragestellung:
wie bekomme ich es nun hin, alle gewünschten spalten (siehe letzte select-anweisung) auszugeben? denn ich müsste ja alle in die group by klausel stecken, welche keine aggregat-funktion haben? und dies führt dann ja dazu, dassmehrere gruppen gebildet werden und somit einige zeilen bzw. mehrere datensätze zu einer personalnummer ausgeworfen werden?

der funzende code:
Code:
SELECT DISTINCT personal.personalnr, MAX(auftrag.vonDatum)
FROM (personal INNER JOIN einsPers ON personal.personalNR=einsPers.personalNr) INNER JOIN auftrag ON auftrag.auftragNr=einsPers.auftragNr  
WHERE (personal.persstatus = 2 OR personal.persstatus = 7)  AND auftrag.auftstatus= 2 
GROUP BY personal.personalnr  				
ORDER BY personal.personalnr ASC
 
Edit: habs mir nochmal überlegt und macht kein Sinn was ich schrieb :(
Ich glaub du müsstest eine Unteranweisung machen, aber genau kann ichs dir niicht sagen weil ich mich nicht mehr erinnern kann und ohen die Tabellen kannich es mir auchnicht so vorstellen^^
 
Last edited:
Bin auch nicht so der SQL pro... und ohne Tabellen oder wenigstens ein Datenmodell ist es sowieso schwer nachzuvollziehen. Ob das was du jetzt hast optimal ist kann ich auch nicht sagen.
Eine Möglichkeit das Ergebnistupel um weitere gewünschte Spalten zu erweitern wäre glaube ich, deine jetzige Abfrage als Subselect zu Nutzen, in etwa so:
Select „gewünschte Spalten“ FROM „dafür benötigte Tabellen WHERE "eindeutig identifizierbarer wert, also entweder nur pernr. oder die kombi wie im subselect - abh von datenbankstruktur" IN (dein Select)
 
zur struktur der tabellen:
die primärschlüssel sind bei auftrag=auftragnr und bei personal=personalnr.
genutzte fremdschlüssel sieht man ja in der from-klausel.
hm, reicht das in kombo mit den genannten spalten?

jedenfalls habe ich mir deinen vorschlag bzgl. IN-klausel angeshen und ausprobiert. der haken: das geht nur mti einer spalte, also bei mir nciht, weil ja eben für SELECT und GROUP BY 2 spalten notwendig sind :(
so in etwa:
Code:
SELECT DISTINCT personal.personalnr, personal.nachname, personal.vorname, personal.kostenst AS KS_Personal,  personal.eintritt1, personal.persstatus, auftrag.auftragnr, auftrag.kostenst AS KS_Auftrag, auftrag.vonDatum AS vonDatum
FROM (personal INNER JOIN einsPers ON personal.personalNR=einsPers.personalNr) INNER JOIN auftrag ON auftrag.auftragNr=einsPers.auftragNr  
WHERE [COLOR="Red"]personal.personalnr, auftrag.vonDatum IN 
(
SELECT DISTINCT personal.personalnr, MAX(auftrag.vonDatum)[/COLOR]
FROM (personal INNER JOIN einsPers ON personal.personalNR=einsPers.personalNr) INNER JOIN auftrag ON auftrag.auftragNr=einsPers.auftragNr  
WHERE (personal.persstatus = 2 OR personal.persstatus = 7)  AND auftrag.auftstatus= 2 
GROUP BY personal.personalnr
) 				    		
ORDER BY personal.nachname ASC
 
Mit Klammern dürfte es gehen. Tut es zumindestens bei mir.

Code:
SELECT DISTINCT personal.personalnr, personal.nachname, personal.vorname, personal.kostenst AS KS_Personal,  personal.eintritt1, personal.persstatus, auftrag.auftragnr, auftrag.kostenst AS KS_Auftrag, auftrag.vonDatum AS vonDatum
FROM (personal INNER JOIN einsPers ON personal.personalNR=einsPers.personalNr) INNER JOIN auftrag ON auftrag.auftragNr=einsPers.auftragNr  
WHERE [COLOR="Red"]([/COLOR]personal.personalnr, auftrag.vonDatum[COLOR="Red"])[/COLOR] IN 
(
SELECT DISTINCT personal.personalnr, MAX(auftrag.vonDatum)
FROM (personal INNER JOIN einsPers ON personal.personalNR=einsPers.personalNr) INNER JOIN auftrag ON auftrag.auftragNr=einsPers.auftragNr  
WHERE (personal.persstatus = 2 OR personal.persstatus = 7)  AND auftrag.auftstatus= 2 
GROUP BY personal.personalnr
) 				    		
ORDER BY personal.nachname ASC
 
hm, bei mir irgendwie nicht. wobei ich erst dachte, dass vor IN grundsätzlich nur ein ausdruck akzeptiert würde. aber dann habe ich doch noch ein bsp gefunden, was deinen vorschlag untermauert. womit testest du das eigentlich? hätte auch gerne ne einfache entwicklungsumgebung für sql, denn dieser editor hier ist es noch nichtmal wert, wegen ihm zu brechen.
und HAVING funzt übrigens doch. arghhhh
hm, aber das bringt mri wohl eh nix :?
 
Ich nutze (gezwungenermaßen: Studium) postgresql (pgAdmin), ist jetzt nicht unbedingt soooo premium, aber man kann damit arbeiten.

Folgendes geht bei mir:
SELECT * FROM gesetzteshaus WHERE (x,y) IN (SELECT x,y FROM wohnen)

Der Ausdruck vor WHERE muss aber wohl entgegen meines obigen Posts den Ergebnisspalten im Subselect entsprechen. Folgendes ginge nicht:
SELECT * FROM gesetzteshaus WHERE x IN (SELECT x,y FROM wohnen)


edit:
Habe mir dein Select gerade mal angeguckt und meiner Meinung nach, müssten überall auch natural joins gehen, da die Spaltennamen gleich sind. das ständige referenzieren von attributnamen auf spezielle Tabellen ist auch unnötig (wird beim Problem wohl nicht weiterhelfen, machts aber übersichtlicher). Ich würde den Fehler im inneren select vermuten, habe aber ehrlich gesagt immernoch nicht so wirklich gepeilt, was du da raussuchen willst mit dem MAX(vonDatum). :(

SELECT DISTINCT personalnr, nachname, vorname, kostenst AS KS_Personal, eintritt1, persstatus,
auftragnr, kostenst AS KS_Auftrag, vonDatum AS vonDatum //(warum?)
FROM personal NATURAL JOIN einsPers NATURAL JOIN auftrag
WHERE (personalnr, vonDatum) IN
(
SELECT DISTINCT personalnr, MAX(vonDatum)
FROM personal NATURAL JOIN einsPers NATURAL JOIN auftrag
WHERE (persstatus = 2 OR personal.persstatus = 7) AND auftrag.auftstatus= 2
GROUP BY personal.personalnr
)
ORDER BY nachname ASC
 
Last edited:
Folgendes geht bei mir:
SELECT * FROM gesetzteshaus WHERE (x,y) IN (SELECT x,y FROM wohnen)

Der Ausdruck vor WHERE muss aber wohl entgegen meines obigen Posts den Ergebnisspalten im Subselect entsprechen. Folgendes ginge nicht:
SELECT * FROM gesetzteshaus WHERE x IN (SELECT x,y FROM wohnen)

öh, tut er doch :?
 
Jo, war nur ne generelle Anmerkung.

Habe oben noch was reineditiert, was das Query übersichtlicher machen könnte. Was bei uns noch ne Fehlerquelle war, aber wohl eher an pgAdmin lag, war Camelschreibweise in Tabellennamen wie du es in einsPers hast, das ging nur wenn man es in Anführungszeichen schreibt.
 
die genaue fehler meldung ist, dass er das "," hier nicht erkennt(unknown token):
Code:
WHERE (personal.personalnr[COLOR="Red"],[/COLOR] auftrag.vonDatum) IN 
(
SELECT DISTINCT personal.personalnr, MAX(auftrag.vonDatum)


mit NATURAL kann der nix anfangen. es geht nur mit INNER in kombo mit ON.
der is nicht case-sensitiv. ob ich code, bezeichner, werte oder sonstiges groß oder klein schreibe juckt in keinster weise. dient mri also nur zur überischtlichkeit.
die referenzen auf die verschiedenen tabellen macht durchaus sinn (wenn auch nciht bei jeder, habe die überflüssigen mal rausgenommen), weil zb die kostenstelle eines auftrages und die des personals durchaus unterschiedlich sein können, aber eben gleich heißen.

Das eigentliche Ziel:
Es gibt Mitarbeiter=Personal.
Es gibt Aufträge=Auftrag.
Es gibt einen Einsatzplan fürs Personal, also an welchem Auftrag sie arbeiten=einsPers. Letztere Tabelle beinhaltet also sämtliche (0-n) Mitarbeiter zu einem (1-1) Auftrag.
Die Abfrage dient nun dazu, rauszufinden, an welchem Auftrag welcher MA gerade (und seit wann) arbeitet. MAX(vonDatum) zeigt ja das aktuellste Startdatum eines MA an.
 
Wenn es Spalten in verschiedenen Tabellen gibt, die gleich heißen aber andere Bedeutungen haben,wäre ein natural join sowieso kontraproduktiv. trotzdem komisch, dass dein program das nicht kennt... der kommafehler erscheint mir ebenfalls sinnlos. machst du das für die arbeit, als hausaufgabe oder einfach nur so? sprich: bist du irgendwie daran gebunden oder könntest du die datenbank auch einfach woanders anlegen?

Hm, ja meine Ideen sind so langsam erschöpft. Versuch doch ansonsten mal auf einem Fachboard Hilfe zu kriegen. tutorials.de oder so...
 
ich mache das für die arbeit. hat glücklicher weise nicht so die eile. das prob hier ist wie gesagt, dass die syntax bzw. die verwendbaren klauseln einigermaßen weit weg vom sql-standard sind :(
aber ich bedanke mich auf jeden vorerst für deine hilfe :wub
hast mir neue wege aufgezeigt. gibt auch lecker reno :D
wenn cih was neues finde werde ichs heir posten...
 
Ähm... is jetzt mal frei heraus geschossen, aber du musst das WHERE weg lassen wenn du mit HAVING arbeitest, da HAVING nix anderes ist als WHERE, nur für dein GROUP BY.
Hat bei mir damals auch nie wirklich gefunzt, bis ich das was ich im WHERE definieren wollte einfach beim HAVING rein gepackt hatte.
 
Könnt ihr sowas nicht mal schön formatieren? Wer soll denn da noch durchblicken ...

Also ich würde es so schreiben:
Code:
SELECT
	personal.`personalnr`,
	personal.`nachname`,
	personal.`vorname`,
	personal.`kostenst` AS `KS_Personal`,
	personal.`eintritt1`,
	personal.`persstatus`,
	auftrag.`auftragnr`,
	auftrag.`kostenst` AS `KS_Auftrag`,
	auftrag.`vonDatum` AS `vonDatum`
FROM
	`personal`
	INNER JOIN
		`einsPers`
		ON
			personal.`personalnr` = einsPers.`personalnr`
	INNER JOIN
		(
			SELECT
				personal.`personalnr`,
				auftrag.`auftragnr`,
				MAX(auftrag.`vonDatum`) AS `vonDatum`
			FROM
				`personal`,
				`einsPers`,
				`auftrag`
			WHERE
				(
						personal.`persstatus` = 2
					OR 	personal.`persstatus` = 7
				)
				AND auftrag.`auftstatus` = 2
				AND personal.`personalnr` = einsPers.`personalnr`
				AND auftrag.`auftragnr` = einsPers.`auftragnr`
			GROUP BY
				personal.`personalnr`
		) AS `innerauftrag`
		ON
				innerauftrag.`personalnr` = einsPers.`personalnr`
			AND	innerauftrag.`auftragnr` = einsPers.`auftragnr`
	INNER JOIN
		`auftrag`
		ON
			auftrag.`vonDatum` = innerauftrag.`vonDatum`
ORDER BY
	personal.`nachname`
	ASC

Ohne Information über die Datenbank kann meine Glaskugel das aber auch nur bedingt bestimmen.
 
najo, die syntax bei sql unterscheidet sich natürlich von richtigen programmiersprachen :)
aber dass sowas wie nen subselect inner from-klausel funzt war mir nicht bekannt. ich werde es nachher testen :top
schon mal 1000 dank für die mühen :sun
@edit:
aber was für nen join versprichst du dir denn von dem subselect ?
 
Last edited:
Das Subselect gibt die größten "auftrag.`vonDatum`" Werte mit zugeordneter "personal.`personalnr`" und "auftrag.`auftragnr`" zurück.

Durch die ON-Klausel bekommen man denn die "auftrag.`auftragnr`" zum größten "auftrag.`vonDatum`" der jeweiligen Person zurück.
Diesen kann man dann im weiteren JOIN nutzen und tatsächlich auch die weiteren Daten ("auftrag.`kostenst`") zum größten "auftrag.`vonDatum`" der zugehörigen "auftrag.`auftragnr`" auslesen.

Wenn du kein HAVING nutzen kannst wirst du auf ein Subselect angewiesen sein, solange du es nicht auf zwei Anfragen aufspalten willst.
 
Back
Top Bottom