È possibile ottenere il risultato utilizzando una query SQL, ma non è banale.
Ma prima di intraprendere quella strada, ti consiglio di considerare un approccio diverso.
Poiché la query restituisce un set di righe relativamente piccolo, puoi invece recuperare l'intero set di risultati in PHP come un array bidimensionale.
Considera un caso abbastanza semplice, a titolo esemplificativo:
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
Potremmo eseguire un fetchAll e ottenere un array bidimensionale, quindi scorrere l'array e recuperare i valori in base alla colonna, anziché in base alla riga. Un'opzione è trasformare l'array che riceviamo in un nuovo array simile a questo:
bar ABC DEF
--- --- ---
fee 2 11
fi 3 13
fo 5 17
fum 7 19
Non è davvero necessario eseguire la trasformazione, potresti percorrere l'array originale. Ma separare la trasformazione come un passaggio separato probabilmente renderebbe il tuo codice un po' più semplice, quando arrivi a generare effettivamente l'output nella pagina. (Sembra un problema abbastanza comune che qualcuno abbia probabilmente scritto una funzione che esegua la trasformazione dell'array desiderata. Non credo che ci sia un builtin PHP che lo faccia.
titoli:
array { [0]=>'bar' [1]=>'ABC' [2]=>'DEF' }
righe:
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' }
}
Per un piccolo insieme di righe come te, sceglierei di farlo in PHP anziché in SQL.
Ma hai chiesto come farlo in SQL. Come ho detto prima, non è banale.
SQL richiede che l'istruzione SELECT definisca ogni colonna da restituire; il numero ei tipi delle colonne non possono essere dinamici quando l'istruzione viene eseguita.
Se costruiamo un'altra query (a parte la query originale) che definisce le colonne e restituisce le righe che ci aspettiamo restituite con i segnaposto per i valori, siamo a metà strada. Non resta che eseguire un outer join alle righe restituite dalla query originale e restituire condizionalmente i valori delle colonne sulle righe appropriate.
Questo approccio funziona se hai un set predefinito di righe e colonne che dobbiamo restituire, specialmente quando l'origine della riga originale è sparsa e dobbiamo generare le righe "mancanti". (Ad esempio, ottenendo il conteggio dei prodotti ordinati e ci sono molte righe mancanti, non c'è un buon modo per generare le righe mancanti.
Ad esempio:
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
Quello tornerà:
bar ABC DEF
--- --- ---
fee
fi
fo
fum
Quindi, questo ci ottiene tutte le colonne definite e tutte le righe che vogliamo restituire. La prima colonna è popolata. Quella query non ha ancora davvero bisogno di GROUP BY, ma ne avremo bisogno una volta che avremo abbinato le righe dal set di risultati di origine "reale".
Il "trucco" ora è abbinare le righe dalla nostra fonte e restituire il valore da una colonna in base alle condizioni appropriate.
Quello che andremo a generare è essenzialmente un set di risultati simile a questo:
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
Quindi andremo a "comprimere" le righe, rimuovendo la colonna foo dal set di risultati ed eseguendo un GROUP BY su bar
. Utilizzeremo una funzione di aggregazione (MAX o SUM) sfruttando la gestione che fanno con i valori NULL, per produrre un risultato come questo:
bar foo ABC DEF
--- --- --- ---
fee 2 11
fi 3 13
fo 5 15
fum 7 17
Usando questo SQL piuttosto ingombrante:
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
Nota che mysource
nella query sopra può essere sostituita con una vista in linea, avvolgendo le parentesi attorno a una query adatta che restituisce le righe desiderate.
La vista in linea alias come r
è la nostra fonte per restituire le righe che vogliamo restituire.
Le espressioni nell'elenco SELECT stanno eseguendo i test condizionali, per selezionare i valori corretti per ogni colonna in ogni riga.
Dato il modello regolare delle istruzioni CASE, è possibile utilizzare alcuni SQL per aiutare a generare la query, ma questo deve essere fatto come un passaggio separato. L'output di tale SQL può essere utilizzato per aiutare a formare la query effettiva di cui abbiamo bisogno.
Nel tuo caso, dato che workdate
è quello che vuoi usare per l'intestazione della colonna, probabilmente questo dovrà essere generato dinamicamente. (Puoi eliminare la seconda colonna "giorno della settimana" dalla query di origine originale e spostarla nella query esterna.
Se non conoscessi il workdate
valori per le intestazioni prima di eseguire la query, quindi sceglierei di creare una TABELLA TEMPORANEA e popolarla con i risultati della query originale, quindi eseguire una query sulla tabella temporanea per ottenere la workdate
intestazioni e la "prima colonna" per generare le righe. Quindi eseguirei la query effettiva sulla tabella temporanea.
Per ripetere, penso che faresti meglio a fare la trasformazione/pivot dei risultati dalla tua query originale in PHP, piuttosto che provare a farlo in SQL.