Frage zu Joins

Tommy57

Erfahrenes Mitglied
Hi Leute,

ich hab da mal eine allgemeine Frage:

Wenn ich eine Tabelle habe mit lauter Tageswerten von Aktienkursen und ich mit einem Statement von allen Kursen alle letzten Werte holen will, die zB gestern, vorgestern, letzte Woche, vor zwei Wochen und vor einem Monat lagen und ich NICHT an jedem Tag einen Wert habe, muss ich dann zu jedem gewünschten Datum erst den MAX (tag) holen und dann in einem weiteren JOIN den Wert am jeweiligen Tag?


Meine Statements werden dadurch schnell mal riesig lang.

Beispiel:

id_indice, day_of_value, value
1, 2013-01-14, 123.45
1, 2013-01-12, 123.37
2, 2013-01-14, 97.23
2, 2013-01-13, 97.26
usw

Code:
SELECT
    y0.id_indice,
    y0.lastday,
    y1.value AS lastdayvalue
FROM
    (SELECT
        x0.id_indice,
        MAX(x1.day_of_value) AS lastday
    FROM
        (SELECT
           id_indice
        FROM
           indices) x0
    INNER JOIN
        indicevalues x1
    ON
        x1.id_indice = x0.id_indice) y0
INNER JOIN
    indicevalues y1
ON
    y1.id_indice = y0.id_indice
AND
    y1.day_of_value = y0.lastday

Wäre echt super, wenn mir da mal jemand helfen könnte. Weil ich mittlerweile Statements über 100 Zeilen habe die super funktionieren und auch sehr schnell sind, aber sich nur extrem schwer anpassen lassen, da meine Spalten in den Statements immer weiter hochgereicht werden. Das geht bestimmt noch besser.

Gruß, Tommy
 
Ich versteh die Frage nicht. Grundsätzlich ist das schon die richtige Vorgehensweise.
Die Tage zurück (-1 Tag, -1 Monat) etc. Sind diese immer gleich? Brauchst due mehrere von diesen in einem Statement?

Eine mögliche Lösung
Zuerst mal die Datums ermitteln
SQL:
SELECT 'heute' AS name, DATE(SYSDATE()) AS as_of_date, 0 AS sort
UNION SELECT 'gestern', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 DAY)), 1
UNION SELECT 'letzte Woche', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 WEEK)), 2
UNION SELECT 'letzter Monat', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 MONTH)), 3

Und dann zum inneren SQL hinzufügen.

Kannst du mir mal sagen was das folgende macht?
SQL:
SELECT
    x0.id_indice,
    MAX(x1.day_of_value) AS lastday
FROM
    (SELECT id_indice FROM indices) x0
	INNER JOIN indicevalues x1
		ON x1.id_indice = x0.id_indice
 
Zuletzt bearbeitet von einem Moderator:
Hi Yaslaw,

ja, die gesuchten Tage sind immer die gleichen Intervalle (vor einem Tag, vor 7 Tagen usw.), aber es gilt folgendes: Wenn ich zum Beispiel den Wert vor 7 Tagen brauche, nehme ich den Wert vom höchsten Datum vor 7 Tagen, den ich finden kann. Das könnte aber auch der von vor 8-9 Tagen sein.

Code:
SELECT
    x0.id_indice,
    MAX(x1.day_of_value) AS lastday
FROM
    (SELECT id_indice FROM indices) x0
    INNER JOIN indicevalues x1
        ON x1.id_indice = x0.id_indice

Erst mal hole ich aus einer anderen Tabelle alle benötigten Kurse. Danach werden die mit jeweils dem letzten Datum gejoined, der in der Datenbank gelistet ist. Im nächsten Schritt mache ich dann einen Join mit genau diesem Datum, um den dazugehörigen Wert auszulesen. Das Datum ist eigentlich unwichtig, ich brauche das nur für die Joins, um an die gesuchten Werte zu kommen.
Diesen Vorgang wiederhole ich dann etwa 4 mal mit zB gestern, letzter Woche, vor einem Monat und vor drei Monaten, um am Ende die Werte gegeneinander aufzurechnen um zum Beispiel Entwicklungen zu berechnen.

Hoffe, das ist verständlich. Echt schwierig sowas zu beschreiben.

Gruß, Tommy
 
Also es gibt eine Tabelle, wo alle Kurse mit ID, Namen, usw. gelistet sind. In dieser Tabelle stehen diverse Informationen zu den einzelnen Kursen.
Dann gibt es noch eine weitere Tabelle, wo alle Tageswerte der Kurse stehen. Diese Tabelle sieht so aus:

ID;day_of_value;value;
1; 2013-01-15;123.45;
1;2013-01-14;123.47;
1;2013-01-12;123.44;
 
Gut, jetzt versteh ich glaub was du willst. Die Tabelle indices brauchst du erst ganz am Schluss
Zuerst setzen wir eine Tabelle auf die deine Zeitstempfel beinhaltet die du ausgeben willst.
Unter MySQL würde diese so aussehen
SQL:
SELECT 'heute' AS name, DATE(SYSDATE()) AS as_of_date, 0 AS sort
UNION SELECT 'gestern', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 DAY)), 1
UNION SELECT 'letzte Woche', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 WEEK)), 2
UNION SELECT 'letzter Monat', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 MONTH)), 3
-- für jede gewünschte Periode einen weitere UNION

Dann diese mit der Tabelle indicevalues verbinden.
SQL:
SELECT
	d.as_of_date,
	d.name,
	d.sort,
	i.id_indice,
	i.day_of_value
FROM
    indicevalues AS i,
    (
    	SELECT 'heute' AS name, DATE(SYSDATE()) AS as_of_date, 0 AS sort
		UNION SELECT 'gestern', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 DAY)), 1
		UNION SELECT 'letzte Woche', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 WEEK)), 2
		UNION SELECT 'letzter Monat', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 MONTH)), 3
	) AS d
WHERE 
	d.as_of_date >= i.day_of_value

Das aganze gruppieren und jewils das höchste day_of_value ermitteln
SQL:
SELECT
	d.as_of_date,
	d.name,
	d.sort,
	i.id_indice,
	MAX(i.day_of_value) AS max_day_of_value
FROM
    indicevalues AS i,
    (
    	SELECT 'heute' AS name, DATE(SYSDATE()) AS as_of_date, 0 AS sort
		UNION SELECT 'gestern', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 DAY)), 1
		UNION SELECT 'letzte Woche', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 WEEK)), 2
		UNION SELECT 'letzter Monat', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 MONTH)), 3
	) AS d
WHERE 
	d.as_of_date >= i.day_of_value
GROUP BY
	d.as_of_date,
	d.name,
	d.sort,
	i.id_indice

Und dieses jetzt wieder mit zurückverknüpfen um den value zu ermitteln. Dabei können wir auch gleich die Tabelle indices anhängen
SQL:
SELECT
	ii.*,
	iv.day_of_value,
	iv.value,
	ld.name,
	ld.as_of_date
FROM
	id_indice AS ii,
	indicevalues AS iv,
	(
		SELECT
			d.as_of_date,
			d.name,
			d.sort,
			i.id_indice,
			MAX(i.day_of_value) AS max_day_of_value
		FROM
		    indicevalues AS i,
		    (
		    	SELECT 'heute' AS name, DATE(SYSDATE()) AS as_of_date, 0 AS sort
				UNION SELECT 'gestern', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 DAY)), 1
				UNION SELECT 'letzte Woche', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 WEEK)), 2
				UNION SELECT 'letzter Monat', DATE(DATE_SUB(SYSDATE(), INTERVAL 1 MONTH)), 3
			) AS d
		WHERE 
			d.as_of_date >= i.day_of_value
		GROUP BY
			d.as_of_date,
			d.name,
			d.sort,
			i.id_indice	
	) AS ld
WHERE
	ii.id_indice = ld.id_indice
	AND iv.id_indice = ld.id_indice
	AND iv.day_of_value = ld.max_day_of_value
ORDER BY
	ld.sort

Das ganze ist natürlich wie eh immer ungetestet...
 
Zuletzt bearbeitet von einem Moderator:
Das ist ja cool. Ich habe was länger gebraucht, um das zu verstehen...

Du benutzt die gesuchten Tage als Hilfsspalte quasi. Das ist echt genial.

1000 Dank für diesen Tipp. Du ersparst mir damit so unglaublich viel Arbeit. Vielen Dank!

Gruß, Adnan
 

Neue Beiträge

Zurück