Vinzenz Mai: Kreuztabelle? Oder doch nicht

Beitrag lesen

Hallo,

Frage an die Datenbankexperten bezüglich eines INNER JOIN

messreihe lambda messung
2 1.7 2.55
2 1.8 3.45
2 1.9 4,32
3 1.7 3.21
3 1.8 2.89
3 1.9 1.42
5 1.7 3.86
5 1.8 2.28
5 1.9 1.12

Eigentlich sind es mehrere Millionen Einträge.
Mein Wunschergebnis sieht so aus:

| lambda | messreihe2 | messreihe3 | messreihe5 |
| 1.7    | 2.55       | 3.21       | 3.86       |
| 1.8    | 3.45       | 2.89       | 2.28       |
| 1.9    | 4.32       | 1.42       | 1.12       |

Sieht nach einer Kreuztabelle aus :-)
MySQL bietet keine eingebaute Unterstützung für Kreuztabellen :-(

Gehe ich nun davon aus, dass auf der Spaltenkombination messreihe, lambda ein kombinierter eindeutiger Index liegt, so gibt es für jedes Tupel (lambda, messreihe) genau einen Wert, den Du anzeigen möchtest.

Da Du für jeden lambda-Wert eine einzige Zeile haben willst, ist eine Gruppierung nach lambda erforderlich. Für jeden unterschiedlichen Wert der Spalte messreihe willst Du eine eigene Spalte erzeugen.

Da Du eine Gruppierung verwendest, solltest Du auf die weiteren Spalten eine Aggregatsfunktion anwenden (auch wenn MySQL das nicht unbedingt haben will). MAX, MIN, AVG sollten alle den einzigen vorhandenen Wert liefern. Ich verwende einfach MAX.

Bei Deinen Beispieldaten sähe das Statement wie folgt aus:

  
SELECT       Gib mir zu jedem unterschiedlichen Wert der Spalte  
    lambda,  -- lambda  
    -- berücksichtige nur Zeilen mit dem Wert 2 in Messreihe  
    -- und von allen diesen Zeilen hätte ich nur das Maximum  
    -- (das ja genau einmal zu einem lambda-Wert vorkommt)  
    -- und benenne diese Reihe messreihe2  
    MAX(CASE WHEN messreihe = 2 THEN messung ELSE NULL END) AS messreihe2,  
    -- berücksichtige nur Zeilen mit dem Wert 3 in Messreihe  
    -- und von allen diesen Zeilen hätte ich nur das Maximum  
    -- (das ja genau einmal zu einem lambda-Wert vorkommt)  
    -- und benenne diese Reihe messreihe3  
    MAX(CASE WHEN messreihe = 3 THEN messung ELSE NULL END) AS messreihe3,  
    -- analog für 5  
    MAX(CASE WHEN messreihe = 5 THEN messung ELSE NULL END) AS messreihe5  
FROM  
    daten  
GROUP BY lambda  

Dies liefert das gewünschte Resultat.

| lambda | messreihe2 | messreihe3 | messreihe5 |
| 1.7    | 2.55       | 3.21       | 3.86       |
| 1.8    | 3.45       | 2.89       | 2.28       |
| 1.9    | 4.32       | 1.42       | 1.12       |

Auf die Aggregatsfunktion kannst Du auch unter MySQL nicht verzichten, das in dieser Hinsicht ja großzügig ist, weil nicht garantiert ist, ob der Wert aus messung oder NULL genommen wird. Jedenfalls zeigt das um die Kommentare bereinigte Statement die Systematik, nach der Du Dein Gesamtstatement dynamisch zusammenbauen könntest:

  
SELECT  
    lambda,  
    MAX(CASE WHEN messreihe = 2 THEN messung ELSE NULL END) AS messreihe2,  
    MAX(CASE WHEN messreihe = 3 THEN messung ELSE NULL END) AS messreihe3,  
    MAX(CASE WHEN messreihe = 5 THEN messung ELSE NULL END) AS messreihe5  
FROM  
    daten  
GROUP BY lambda  

wobei Du die unterschiedlichen Werte in messreihe, aufsteigend sortiert verwendest, wie sie Dir

  
SELECT DISTINCT  
    messreihe  
FROM  
    daten  
ORDER BY  
    messreihe  

Ergebnis:

messreihe
---------
    2
    3
    5

oder alternativ

  
SELECT  
    messreihe  
FROM  
    daten  
GROUP BY  
    messreihe  

liefern, da eine GROUP-BY-Spalte in MySQL implizit eine Sortierung nach dieser Spalte verursacht.

Die notwendige Abfrage nach dem Schema

  
SELECT  
    lambda,  
    MAX(CASE WHEN messreihe = 2 THEN messung ELSE NULL END) AS messreihe2,  
    MAX(CASE WHEN messreihe = 3 THEN messung ELSE NULL END) AS messreihe3,  
    MAX(CASE WHEN messreihe = 5 THEN messung ELSE NULL END) AS messreihe5  
FROM  
    daten  
GROUP BY lambda  

solltest Du in PHP somit bequem zusammenbauen können. Mit Hilfe einer Stored Procedure und einem Cursor über das Ergebnis der anderen Abfrage könntest Du
dies auch hinbekommen, aber ich bezweifle, dass sich der Aufwand lohnt. Für ein vergleichbares Problem beim MS SQL-Server 2000 habe ich mal was gepostet.

Eine SP, die eine beliebige Kreuzabfrage zusammenbaut, wäre schon ganz nett. Da muss man aber alle Eventualitäten berücksichtigen. Es dürfte nicht trivial sein.

Weiterhin solltest Du unbedingt die Performance dieser Abfrage mit Deiner Datenmenge prüfen, und mit Hilfe von EXPLAIN schauen, ob Indexe genutzt werden können.

Freundliche Grüße

Vinzenz