Es ist möglich, das Ergebnis mit einer SQL-Abfrage zu erhalten, aber es ist nicht trivial.
Aber bevor Sie diesen Weg gehen, empfehle ich Ihnen, einen anderen Ansatz in Betracht zu ziehen.
Da die Abfrage eine relativ kleine Menge von Zeilen zurückgibt, könnten Sie stattdessen die gesamte Ergebnismenge als zweidimensionales Array in PHP abrufen.
Betrachten Sie zur Veranschaulichung einen ziemlich einfachen Fall:
SELECT foo, fee, fi, fo, fum
FROM mytable
ORDER BY foo
foo fee fi fo fum
--- --- --- --- ---
ABC 2 3 5 7
DEF 11 13 17 19
Wir könnten ein fetchAll ausführen und ein zweidimensionales Array erhalten, dann das Array durchlaufen und die Werte spaltenweise statt zeilenweise abrufen. Eine Möglichkeit besteht darin, das Array, das wir erhalten, in ein neues Array umzuwandeln, das wie folgt aussieht:
bar ABC DEF
--- --- ---
fee 2 11
fi 3 13
fo 5 17
fum 7 19
Es ist nicht wirklich notwendig, die Transformation durchzuführen, Sie könnten das ursprüngliche Array durchlaufen. Aber die Umwandlung in einen separaten Schritt zu unterteilen, würde Ihren Code wahrscheinlich etwas einfacher machen, wenn Sie die Ausgabe tatsächlich auf der Seite generieren. (Es scheint ein ziemlich häufiges Problem zu sein, dass jemand wahrscheinlich eine Funktion geschrieben hat, die die gewünschte Array-Transformation durchführt. Ich glaube nicht, dass es ein PHP-Buildin gibt, das dies tut.
Überschriften:
array { [0]=>'bar' [1]=>'ABC' [2]=>'DEF' }
Zeilen:
array {
[0]=>array { [0]=>'fee' [1]=>'2' [2]=>'11' }
[1]=>array { [0]=>'fi' [1]=>'3' [2]=>'13' }
[2]=>array { [0]=>'fo' [1]=>'5' [2]=>'17' }
[3]=>array { [0]=>'fum' [1]=>'7' [2]=>'19' }
}
Für eine kleine Reihe von Zeilen, wie Sie sie haben, würde ich mich dafür entscheiden, dies in PHP statt in SQL zu tun.
Aber Sie haben gefragt, wie man es in SQL macht. Wie ich bereits sagte, ist es nicht trivial.
SQL erfordert, dass die SELECT-Anweisung jede zurückzugebende Spalte definiert; Die Anzahl und Typen der Spalten dürfen nicht dynamisch sein, wenn die Anweisung ausgeführt wird.
Wenn wir (abgesehen von der ursprünglichen Abfrage) eine weitere Abfrage erstellen, die die Spalten definiert und die erwarteten Zeilen mit Platzhaltern für die Werte zurückgibt, sind wir schon auf halbem Weg. Es bleibt nur noch, eine äußere Verknüpfung mit den von der ursprünglichen Abfrage zurückgegebenen Zeilen durchzuführen und die Spaltenwerte in den entsprechenden Zeilen bedingt zurückzugeben.
Dieser Ansatz funktioniert, wenn Sie einen vordefinierten Satz von Zeilen und Spalten haben, die wir zurückgeben müssen, insbesondere wenn die ursprüngliche Zeilenquelle spärlich ist und wir die "fehlenden" Zeilen generieren müssen. (Wenn Sie beispielsweise die Anzahl der bestellten Produkte abrufen und viele Zeilen fehlen, gibt es keine gute Möglichkeit, die fehlenden Zeilen zu generieren.
Zum Beispiel:
SELECT r.bar
, '' AS `ABC`
, '' AS `DEF`
FROM ( SELECT 'fee' AS bar
UNION ALL SELECT 'fi'
UNION ALL SELECT 'fo'
UNION ALL SELECT 'fum'
) r
GROUP BY r.bar
Das wird zurückgeben:
bar ABC DEF
--- --- ---
fee
fi
fo
fum
Damit haben wir alle definierten Spalten und alle Zeilen, die wir zurückgeben möchten. Die erste Spalte wird ausgefüllt. Diese Abfrage benötigt das GROUP BY noch nicht wirklich, aber wir werden es brauchen, sobald wir es mit den Zeilen aus der "echten" Quellergebnismenge abgleichen.
Der "Trick" besteht nun darin, die Zeilen aus unserer Quelle abzugleichen und den Wert aus einer Spalte basierend auf den entsprechenden Bedingungen zurückzugeben.
Was wir generieren werden, ist im Wesentlichen eine Ergebnismenge, die wie folgt aussieht:
bar foo ABC DEF
--- --- --- ---
fee ABC 2
fee DEF 11
fi ABC 3
fi DEF 13
fo ABC 5
fo DEF 15
fum ABC 7
fum DEF 17
Dann "reduzieren" wir die Zeilen, indem wir die foo-Spalte aus der Ergebnismenge entfernen und ein GROUP BY auf bar
ausführen . Wir werden eine Aggregatfunktion (entweder MAX oder SUM) verwenden, die den Umgang mit NULL-Werten ausnutzt, um ein Ergebnis wie dieses zu erzeugen:
bar foo ABC DEF
--- --- --- ---
fee 2 11
fi 3 13
fo 5 15
fum 7 17
Verwenden Sie dieses ziemlich unhandliche SQL:
SELECT r.bar
, MAX(CASE WHEN t.foo = 'ABC' THEN CASE r.bar
WHEN 'fee' THEN t.fee
WHEN 'fi' THEN t.fi
WHEN 'fo' THEN t.fo
WHEN 'fum' THEN t.fum
END END) AS 'ABC'
, MAX(CASE WHEN t.foo = 'DEF' THEN CASE r.bar
WHEN 'fee' THEN t.fee
WHEN 'fi' THEN t.fi
WHEN 'fo' THEN t.fo
WHEN 'fum' THEN t.fum
END END) AS 'DEF'
FROM ( SELECT 'foo' AS col
UNION ALL SELECT 'fee'
UNION ALL SELECT 'fi'
UNION ALL SELECT 'fo'
UNION ALL SELECT 'fum'
) r
CROSS
JOIN mysource t
GROUP BY r.bar
Beachten Sie, dass mysource
in der obigen Abfrage kann durch eine Inline-Ansicht ersetzt werden, wobei Klammern um eine geeignete Abfrage gewickelt werden, die die gewünschten Zeilen zurückgibt.
Die Inline-Ansicht mit dem Alias r
ist unsere Quelle für die Rückgabe der Zeilen, die wir zurückgeben möchten.
Die Ausdrücke in der SELECT-Liste führen die bedingten Tests durch, um die richtigen Werte für jede Spalte in jeder Zeile auszuwählen.
Angesichts des regelmäßigen Musters der CASE-Anweisungen ist es möglich, etwas SQL zu verwenden, um die Abfrage zu generieren, aber das muss in einem separaten Schritt erfolgen. Die Ausgabe dieser SQL kann verwendet werden, um bei der Erstellung der eigentlichen Abfrage zu helfen, die wir benötigen.
In Ihrem Fall angesichts dieses workdate
für die Spaltenüberschrift verwenden möchten, muss diese wahrscheinlich dynamisch generiert werden. (Sie könnten diese zweite Spalte „Wochentag“ aus der ursprünglichen Quellabfrage löschen und in die äußere Abfrage verschieben.
Wenn ich das workdate
nicht wüsste Werte für die Überschriften, bevor ich die Abfrage ausführte, dann würde ich mich dafür entscheiden, eine TEMPORARY TABLE zu erstellen und sie mit Ergebnissen aus der ursprünglichen Abfrage zu füllen und dann die temporäre Tabelle abzufragen, um das workdate
zu erhalten Kopfzeilen und die "erste Spalte", um die Zeilen zu generieren. Dann würde ich die eigentliche Abfrage für die temporäre Tabelle ausführen.
Um es noch einmal zu wiederholen, ich denke, Sie sollten die Transformation/Pivotierung der Ergebnisse Ihrer ursprünglichen Abfrage besser in PHP durchführen, als es in SQL zu versuchen.