Frage zu UNION unter MySQL 5.0.24a

redlama

Erfahrenes Mitglied
Hallo zusammen!

Ich versuche mich gerade an einer UNION Abfrage, aber stoße dabei auf ein Problem.
Mein Query sieht wiefolgt aus:
Code:
(
SELECT xy.a, count( yz.b ) AS count1, sum( yz.c ) AS sum1
FROM xy AS xy
LEFT JOIN yz AS yz ON ( xy.a = yz.d )
WHERE yz.e = '0'
GROUP BY xy.a
)
UNION DISTINCT (

SELECT xy.a, count( yz.b ) AS count2, sum( yz.c ) AS sum2
FROM xy AS xy
LEFT JOIN yz AS yz ON ( xy.a = yz.d )
WHERE yz.e = '1'
GROUP BY xy.a
)
UNION DISTINCT (

SELECT xy.a, count( yz.b ) AS count3, sum( yz.c ) AS sum3
FROM xy AS xy
LEFT JOIN yz AS yz ON ( xy.a = yz.d )
WHERE yz.e = '2'
GROUP BY xy.a
)
Dabei bekomme ich folgendes zurück:
Code:
id   	 count1   	 sum1
1   	 1   	    	 7.00
1   	 42   	    	 746.80
1   	 76   	    	 2096.89
Was ich jedoch bräuchte, wäre folgendes:
Code:
id   	 count1   	 sum1   	 count2   	 sum2   	 count3   	 sum3
1   	 1   	    	 7.00   	 42   	    	 746.80   	 76   	    	 2096.89
Hat zufällig jemand eine Idee, wie ich das hinbekomme ohne jedes Query für sich abzusetzen?
 
Zuletzt bearbeitet:
Nein, denn das würde ja bedeuten, dass ich unterschiedliche Tabellen abfrage.
Wie Du vielleicht mitbekommen hast, handelt es sich bei mein Querys immer um die selbe Abfrage, abweichend ist nur der Wert yz.e in der WHERE Klausel.
Die Tabellen sind also auch identisch!
 
Dann pack doch einfach eine View drum. Das könnte vielleicht gehen. (Hab's jetzt selbst noch nicht getestet)
 
Zuletzt bearbeitet:
Mahlzeit

mit Views (in deutschesprachigen Tools auch Sichten genannt :rolleyes: ) kannst du Tabellenausgaben anpassen. Wenn du jetzt eine View erstellst, ungefähr so
Code:
CREATE VIEW v_xy AS select * from xy where xy.z = '1'

kannst du dann mit
Code:
SELECT * FROM xy , v_xy
darauf zugreifen.
Ich hab es mal eben so ähnlich bei mir ausprobiert und so müsste es eigentlich funktionieren. Deine GROUP JOIN und DISTINCT musste dann halt noch entsprechend mit einbauen.
 
Verstehe, dann würde ich aber eine Art temporäre Tabelle bzw. Ergebnistabelle erstellen/kreieren und das will ich nicht!
Deshalb habe ich ja auch versucht die Abfragen per UNION zu verbinden, anstatt sie einzeln abzusetzen, was ich auch tun könnte und was noch einfacher wäre, als ein VIEW zu kreieren.
 
Hallo,

Eine View ist eine gespeicherte Abfrage, die du unter einem Namen aufrufen kannst. Darin können nun auch schon Tabellen verknüpft sein, so dass man dies nicht mehr in jeder Abfrage selbst tun muss.

Dein beschriebenes Problem ist aber eher eins, dass ich als Pivotisieren einer Tabelle bezeichne. D.h. aus Informationen, die über meherere Records verteilt sind, mehrere benannte (neue) Spalten erzeugen oder auch umgekehrt.

In deinem Falle geht man z.B. folgendermassen vor.

Zuallererst versuchst du innerhalb der einzelnen UNION-Statements eine zusätzliche (konstante) Spalte einzuführen, um später eine Unterscheidungsmöglichkeit zu haben:

Statt
SQL:
SELECT xy.a, count( yz.b ) AS count1, sum( yz.c ) AS sum1
....
GROUP BY xy.a

erweitesrt du deine SELECT-Klausel und dementsprechend auch dein GROUP-BY-Klausel:
SQL:
SELECT xy.a, count( yz.b ) AS anz, 'tab1' AS tabname, sum( yz.c ) AS sum
...
GROUP BY xy.a,tabname

Das machst du mit jeder der UNIONs

Am Ende baust du dein ganzes bisheriges Statement in eine Subquery in der FROM-Klausel. Das sieht dann z.B. so aus:

SQL:
SELECT a, anz, tabname FROM (
  SELECT xy.a, count( yz.b ) AS anz, 'tab1' AS tabname, sum( yz.c ) AS sum
...
  GROUP BY xy.a,tabname
  UNION 

....
) gesamt

Wichtig ist der Alias am Ende ("gesamt").

Bis jetzt sieht das Ergebnis deiner Abfrage genauso aus, wie ohne Subquery. Der Trick besteht nun darin, aus den vorhanden Records neue Spalten zu erzeugen:
Der Hintergrund hier ist, dass man als Erkennungszeichen, ob die Ergebnisse aus der ersten Query kamen, die neue Spalte "tabname" nutzen kann. In diesem Fall kann ich in MySQL das CASE WHEN oder IF-Statement benutzen, evtl. auch andere (COALESCE, NULLIF etc.)

Ich zeige es im Folgenden am Beispiel des CASE WHEN-Statements.

SQL:
SELECT a, CASE WHEN tabname = 'tab1' THEN anz ELSE NULL END AS anz1
FROM 
(....
)

Ich erzeuge also eine neue "berechnete" Spalte namens "anz1" und als Inhalt erhält diese sofern in dem Record die Spalte "tabname" auf dem Wert "tab1" steht, den Wert des Feldes anz. Das gleiche machst du nun für Ergebniss aus den beiden anderen Subquery, die mit UNION verknünft sind.

Wenn du die Query nun laufen lässt, wirst du sehen, dass du einige NULL-Werte in den Ergebnissen hast. Die kommen durch die verschiedenen CASE-Zweige zustande.
Um diese weg zu rationalisieren, wendet man einen weiteren Trick an:

Statt
SQL:
SELECT a, CASE WHEN tabname = 'tab1' THEN anz ELSE NULL END AS anz1

schreibst du:
SQL:
SELECT a, MAX(CASE WHEN tabname = 'tab1' THEN anz ELSE NULL END) AS anz1

Dabei nutzt du den Effekt aus, das in jeder deiner neuen berechneten Spalten nur ein Wert nicht NULL ist. Damit erhältst du durch MAX() genau den Wert, der in deiner Spalte auftauchen soll.

Jetzt musst du nur noch dafür sorgen, dass die gesamte Anweisung Statement nach "a"
gruppiert wird (xy.a in deiner inneren Abfrage).

Das endgültige Statement könnte also etwa so aussehen (nicht getestet):



SQL:
SELECT a, 
       MAX(CASE WHEN tabname='tab1' THEN anz ELSE NULL END) AS anz1,
       MAX(CASE WHEN tabname='tab2' THEN anz ELSE NULL END) AS anz2,
       MAX(CASE WHEN tabname='tab3' THEN anz ELSE NULL END) AS anz3
FROM (
SELECT xy.a, count( yz.b ) AS anz, 'tab1' AS tabname, sum( yz.c ) AS sum
FROM xy AS xy
LEFT JOIN yz AS yz ON ( xy.a = yz.d )
WHERE yz.e = '0'
GROUP BY xy.a, tabname
)
UNION DISTINCT (

SELECT xy.a, count( yz.b ) AS anz, 'tab2' AS tabname, sum( yz.c ) AS sum
FROM xy AS xy
LEFT JOIN yz AS yz ON ( xy.a = yz.d )
WHERE yz.e = '1'
GROUP BY xy.a, tabname
)
UNION DISTINCT (

SELECT xy.a, count( yz.b ) AS anz, 'tab3' AS tabname, sum( yz.c ) AS sum
FROM xy AS xy
LEFT JOIN yz AS yz ON ( xy.a = yz.d )
WHERE yz.e = '2'
GROUP BY xy.a, tabname )
) gesamt 
GROUP BY a;

Die Summen als extra Spalten zu definieren hab ich mal Dir überlassen, aber das funkioniert auf die gleiche Art und Weise.

Hoffe es hilft,

Markus
 
Das nenne ich mal eine hilfreiche Aussage, vielen Dank!
ich bin gerade am Testen und bekomme jetzt folgenden Fehler:
#1248 - Every derived table must have its own alias

Weiß Du zufällig, wo der da auftreten könnte?
 
Hallo,

ja du musst dem gesamten inneren Statement einen Tabellen-Alias geben.
Eventuell hast du das vergessen.

SQL:
SELECT ...
FROM 
(
....

) gesamt   <---------------------------- den musst du angeben, sonst Fehler

Wenn der Alias fehlt, müsste es deine Fehlermeldung geben.

Markus
 

Neue Beiträge

Zurück