JOIN auf eine Tabelle und Abfrage des letzten gefüllten Wertes

AlexD1979

Erfahrenes Mitglied
Hallo,
Ich denke das ist nicht ganz so easy und ich habe nun schon viel hin- und hergejoint, aber nie das richtige Ergebnis bekommen.
Ich habe eine Tabelle projekt mit Spalten project_id, project_name,... und eine Tabelle project_milestone mit den Spalten project_id, milestone_id,milestone_date

Nun brauche ich eine Abfrage, die mir im Result den letzten, gefüllten Meilenstein UND den nächsten leeren Meilenstein liefert.
Die Tabelle Meilenstein wird bei Neuanlage eines Projekt initial befüllt, d.h. es sind zu bEginn alle Meilensteine bereits in der Tabelle, aber mit leeren milestone_date Feldern.
project_milestone:
project_id | milestone_id | milestone_date
1 | 0 | 2010-05-19 00:00:00
1 | 1 | 2010-05-20 00:00:00
1 | 2 | NULL
1 | 3 | NULL
1 | 4 | NULL


Ich bräuchte also sowas in der Art wie
SELECT
p.project_id, p.project_name,
current_milestone = (SELECT ? FROM project_milestone WHERE ?), -- müsste dann 1 ergeben
next_milestone = (SELECT ? FROM project_milestone WHERE ?) -- müsste dann 2 ergeben
FROM project p
 
Hallo,

ist zwar nicht schön aber sollte das Ergebniss liefern.

SQL:
SELECT
p.projekt_id,
p.projekt_name,
max(case when pm.milestone_date is null then 0 else pm.mildestone_id end) as current_milestone,
min(case when pm.mildestone_date is null then pm.milestone_id else 0 end) as next_milestone
FROM projekt p , projekt_milestone pm
WHERE
pm.projekt_id = p.projekt_id
GROUP BY
p.projekt_id,
p.projekt_name
 
Zuletzt bearbeitet von einem Moderator:
Unter der Annahme, dass die milestone_id die Meilenstein-Reihenfolge abbildet, kann die 2 gesuchten Werte wie folgt ermitteln:

id der letzten Meilensteine aller Projekte
SQL:
SELECT MAX(milestone_id) AS current_milestone
FROM project_milestone
WHERE NOT IS_NULL(milestone_date)
GROUP BY project_id

id der nächsten Meilensteine aller Projekte
SQL:
SELECT MIN(milestone_id) AS next_milestone
FROM project_milestone
WHERE IS_NULL(milestone_date)
GROUP BY project_id

Kombiniert sieht es dann etwa so aus (Achtung, ist nicht getestet!)
SQL:
SELECT
	p.project_id, 
	p.project_name,	
	current.current_milestone,
	next.next_milestone
FROM
	project p
	LEFT JOIN (	SELECT MAX(milestone_id) AS current_milestone
				FROM project_milestone
				WHERE NOT IS_NULL(milestone_date)
				GROUP BY project_id) current
		ON p.project_id = current.project_id
	LEFT JOIN (	SELECT MIN(milestone_id) AS next_milestone
				FROM project_milestone
				WHERE IS_NULL(milestone_date)
				GROUP BY project_id) next
		ON p.project_id = next.project_id

Dein Ansatz würde ich nicht machen, da er sonst für jedes Projekt 2 Queries ausführen muss, was nicht gerade performant ist.
 
Zuletzt bearbeitet von einem Moderator:
hmm wenn ich es richtig sehe, machen unsere querrys das selbe, aber warum müsste meiner 2 mal ausgeführt werden?
Ich hab nur die where clausel in einem case aufgelöst.
 
Hm.. Schlanker als 'Case when then end' gehts mit dem IF(). Dieser intepretiert NULL auch gleich als false.
Zudem darfst du beim MIN() nicht in CASE 0 zurückgeben, da sonst = als kleinste ID genommen wird. Wir können aber NULL nehmen, da NULL beim MIN ignoriert wird
SQL:
MAX(IF(pm.milestone_date, pm.mildestone_id, NULL)) AS current_milestone,
MIN(IF(pm.milestone_date, NULL, pm.mildestone_id)) AS next_milestone
 
Zuletzt bearbeitet von einem Moderator:
Danke für die Tipps, ich werde das mal versuchen.. ich vergaß zu erwähnen dass es sich um einen SQL Server handelt.. die Syntax ist da etwas anders, aber die Denkanstösse von euch helfen schon mal weiter.!!

Unter der Annahme, dass die milestone_id die Meilenstein-Reihenfolge abbildet, kann die 2 gesuchten Werte wie folgt ermitteln:

id der letzten Meilensteine aller Projekte
SQL:
SELECT MAX(milestone_id) AS current_milestone
FROM project_milestone
WHERE NOT IS_NULL(milestone_date)
GROUP BY project_id

id der nächsten Meilensteine aller Projekte
SQL:
SELECT MIN(milestone_id) AS next_milestone
FROM project_milestone
WHERE IS_NULL(milestone_date)
GROUP BY project_id

Kombiniert sieht es dann etwa so aus (Achtung, ist nicht getestet!)
SQL:
SELECT
	p.project_id, 
	p.project_name,	
	current.current_milestone,
	next.next_milestone
FROM
	project p
	LEFT JOIN (	SELECT MAX(milestone_id) AS current_milestone
				FROM project_milestone
				WHERE NOT IS_NULL(milestone_date)
				GROUP BY project_id) current
		ON p.project_id = current.project_id
	LEFT JOIN (	SELECT MIN(milestone_id) AS next_milestone
				FROM project_milestone
				WHERE IS_NULL(milestone_date)
				GROUP BY project_id) next
		ON p.project_id = next.project_id

Dein Ansatz würde ich nicht machen, da er sonst für jedes Projekt 2 Queries ausführen muss, was nicht gerade performant ist.
 
Zuletzt bearbeitet von einem Moderator:
Was für ein SQL Server? MS SQL? Oracle?
Hallo MS SQL 2005
Das mit dem group_by ist für das Beispiel praktikabel, ich habe aber in der finalen Query über 40 Felder in dem Select, die müsste ich dann ja alle in das group_by einhacken oder?
Das mit dem JOIN geht in SQL SERVER nicht so..
Code:
select p.project_id,p.inno_ge_project_name,
max(case when imr.inno_mr_decision_date IS NULL then 0 else imr.milestone_id end) AS passed_milestone,
min(case when imr.inno_mr_decision_date IS NULL then imr.milestone_id else 0 end) AS next_milestone
from innovation_project p, innovation_milestone_review imr
WHERE p.project_id = 15
GROUP BY p.project_id,p.inno_ge_project_name
Liefert mir
15 TEST3 0 0
wenn noch keiner der Milestones gefüllt ist.. in dem Fall müsste passed leer sein und next milestone = 0
 
Hallo MS SQL 2005
Das mit dem group_by ist für das Beispiel praktikabel, ich habe aber in der finalen Query über 40 Felder in dem Select, die müsste ich dann ja alle in das group_by einhacken oder?
Nicht unbedingt.
Man kann auch mit einem JOIN (keine Ahnung wie der im MS SQL geht) nachträglich die Felder dazunehmen

Beispiel für den current_milestone
SQL:
SELECT
	p.*
FROM
	project_milestone p,
	(	SELECT MAX(milestone_id) AS current_milestone
				FROM project_milestone
				WHERE NOT IS_NULL(milestone_date)
				GROUP BY project_id) current
WHERE
	p.project_id = 	current.current_milestone

In meinem JOIN hatte ich noch ein Fehler. Bei der Quelle current, muss natürlich nicht auf projekt_id zugegriffen werden, sondern auf current_milestone
SQL:
        ON p.project_id = current.current_milestone
dito natürlich beim next
 
Zuletzt bearbeitet von einem Moderator:
Zurück