2012-06-07 7 views
21

Ho una tabella retaggio delle informazioni utente (che è ancora in uso attivo) e non posso cambiare la struttura del -mysql selezionare valori di riga dinamici come nomi di colonna, un'altra colonna come valore

id name  value 
------------------------------ 
0  timezone Europe/London 
0  language en 
0  country 45 
0  something x 
1  timezone Europe/Paris 
1  language fr 
1  country 46 

fuso orario/lingua/paese ecc sono solo esempi di nomi, possono essere variabile/non esiste un elenco finito diverso unica sulle righe di quella colonna

ho bisogno di una query SQL compatibile con MySQL che sarebbe tornato -

id timezone  language country something 
--------------------------------------------------- 
0  Europe/London en   45  x 
1  Europe/Paris fr   46 

Ho esaminato varie risposte sullo stackoverflow attorno alle funzionalità della tabella pivot di hacking in MySQL e simili, ma nessuno di essi sembra corrispondere al caso in cui si utilizza l'alias del nome di colonna variabile da valori di riga univoci da una colonna della stessa tabella. Anche se ho dormito poco, tutti cominciano a diventare un po 'sfocati, ci scusiamo in anticipo.

più vicino che ho trovato potrebbe essere quella di utilizzare le istruzioni preparate https://stackoverflow.com/a/986088/830171 che prima ottenere tutti i possibili valori univoci/dalla colonna nome e costruire una query che utilizza CASE WHEN, e/o multipla sub SELECT o JOIN sulle stesse query di tabella.

Le alternative che posso pensare sono di ottenere tutte le righe per quell'id utente e elaborarle nell'applicazione stessa in un ciclo for oppure tentare di limitare i nomi a un numero finito e utilizzare sub-SELECT s/JOIN s. Tuttavia, questa seconda opzione non è l'ideale se viene aggiunto un nuovo nome, dovrei rivisitare questa query.

Ti prego, dimmi che ho perso qualcosa ovvio

+0

Avete davvero bisogno che questo sia espresso in 'sql' o la post-elaborazione sarebbe sufficiente con il vostro linguaggio di programmazione preferito? Se hai bisogno di unirti contro i tuoi dati derattati, allora una vista/proc potrebbe essere il trucco. – bluevector

+0

Sì, per ora manterrò il pasticcio a livello di applicazione - otterrò tutte le righe per quell'id utente e passerò il ciclo sopra mettendo i dati in un array associativo. Volevo solo controllare che fosse l'unica buona opzione. Ancora molto utile avere il metodo SQL per migrazioni e report one-off. – gingerCodeNinja

risposta

39

A differenza di qualche altro RDBMS MySQL non ha il supporto nativo per le operazioni di questo tipo facendo perno dal disegno (gli sviluppatori sentono che è più adatto alla presentazione, piuttosto di database, livello della tua applicazione).

Se è assolutamente necessario perfom tali manipolazioni all'interno di MySQL, la costruzione di una dichiarazione preparata è la strada da percorrere — anche se invece di fare in giro con CASE, probabilmente sarei basta usare la funzione di MySQL GROUP_CONCAT():

SELECT CONCAT(
    'SELECT `table`.id', GROUP_CONCAT(' 
    , `t_', REPLACE(name, '`', '``'), '`.value 
     AS `', REPLACE(name, '`', '``'), '`' 
    SEPARATOR ''), 
' FROM `table` ', GROUP_CONCAT(' 
    LEFT JOIN `table` AS `t_', REPLACE(name, '`', '``'), '` 
      ON `table`.id = `t_', REPLACE(name, '`', '``'), '`.id 
      AND `t_', REPLACE(name, '`', '``'), '`.name = ', QUOTE(name) 
    SEPARATOR ''), 
' GROUP BY `table`.id' 
) INTO @qry FROM (SELECT DISTINCT name FROM `table`) t; 

PREPARE stmt FROM @qry; 
EXECUTE stmt; 

See su sqlfiddle.

Nota che il risultato di GROUP_CONCAT() è limitata dalla group_concat_max_len variabili (di default di 1024 byte: improbabile che possa essere rilevante qui a meno che non si dispone di alcuni estremamente lunghi name valori).

+4

wow - grazie per essersi dedicato a tutto lo sforzo per scrivere e testare una soluzione. Molto apprezzato. Ho sempre voluto sapere come creare questo tipo di query e sembra complicato come immaginavo sarebbe stato. Per ora manterrò il disagio a livello di applicazione, ma questa query sarà ancora molto utile per i rapporti e le migrazioni. Grazie. – gingerCodeNinja

+0

Ho uno scenario molto simile e visualizzo il risultato in rotazione, usando il tuo eccellente esempio.Ma ho bisogno che il risultato venga memorizzato in una tabella perché voglio generare un grafico da esso. È possibile memorizzare il risultato pivot in una tabella? Inoltre, è possibile eseguire sopra in PHP? La mia tabella di origine è user, date, performance e pivot è user come file, data come colonne e performance come valori di cella. – Sri

+0

Ho messo la mia tabella di esempio su sqlfiddle (vedi http://sqlfiddle.com/#!2/06be4/1) – Sri