2013-07-24 19 views
6

Ho cercato molto, ma non ho trovato una soluzione adeguata al mio problema.SQL GROUP_CONCAT diviso in diverse colonne

Che cosa voglio fare?

Ho 2 tabelle in MySQL: - Paese - valuta (Mi unisco a loro insieme tramite CountryCurrency -> a causa di relazione molti a molti)

vedere questo per un esempio di lavoro: http://sqlfiddle.com/#!2/317d3/8/0

Voglio collegare entrambe le tabelle usando un join, ma voglio mostrare solo una riga per paese (alcuni paesi hanno più valute, quindi questo era il primo problema).

ho trovato la funzione group_concat:

SELECT country.Name, country.ISOCode_2, group_concat(currency.name) AS currency 
FROM country 
INNER JOIN countryCurrency ON country.country_id = countryCurrency.country_id 
INNER JOIN currency ON currency.currency_id = countryCurrency.currency_id 
GROUP BY country.name 

Ciò ha il seguente risultato:

NAME   ISOCODE_2 CURRENCY 

Afghanistan AF   Afghani 
Åland Islands AX   Euro 
Albania   AL   Lek 
Algeria   DZ   Algerian Dinar 
American Samoa AS   US Dollar,Kwanza,East Caribbean Dollar 

Ma quello che voglio ora è quella di dividere le valute in diverse colonne (moneta 1, valuta 2, ...). Ho già provato funzioni come MAKE_SET() ma questo non funziona.

+0

SQL non supporta un numero dinamico di colonne. Dovrai farlo nell'applicazione. – Vatev

+0

È possibile utilizzare la logica in un cursore per eseguire questa operazione. Ma il cursore dovrebbe prima esaminare il numero di colonne di dati necessarie per il set di risultati. Crea dinamicamente una tabella temporanea per essere popolata e successivamente selezionata. Un numero indefinito di colonne è il problema di questa sfida. –

risposta

6

È possibile farlo con substring_index(). La seguente query utilizza vostro come una sottoquery e poi applica questa logica:

select Name, ISOCode_2, 
     substring_index(currencies, ',', 1) as Currency1, 
     (case when numc >= 2 then substring_index(substring_index(currencies, ',', 2), ',', -1) end) as Currency2, 
     (case when numc >= 3 then substring_index(substring_index(currencies, ',', 3), ',', -1) end) as Currency3, 
     (case when numc >= 4 then substring_index(substring_index(currencies, ',', 4), ',', -1) end) as Currency4, 
     (case when numc >= 5 then substring_index(substring_index(currencies, ',', 5), ',', -1) end) as Currency5, 
     (case when numc >= 6 then substring_index(substring_index(currencies, ',', 6), ',', -1) end) as Currency6, 
     (case when numc >= 7 then substring_index(substring_index(currencies, ',', 7), ',', -1) end) as Currency7, 
     (case when numc >= 8 then substring_index(substring_index(currencies, ',', 8), ',', -1) end) as Currency8 
from (SELECT country.Name, country.ISOCode_2, group_concat(currency.name) AS currencies, 
      count(*) as numc 
     FROM country 
     INNER JOIN countryCurrency ON country.country_id = countryCurrency.country_id 
     INNER JOIN currency ON currency.currency_id = countryCurrency.currency_id 
     GROUP BY country.name 
    ) t 

L'espressione substring_index(currencies, ',' 2) prende l'elenco in valute fino al secondo. Per American Somoa, sarebbe 'US Dollar,Kwanza'. La prossima chiamata con -1 come argomento prende l'ultimo elemento della lista, che sarebbe 'Kwanza', che è il secondo elemento di currencies.

Si noti inoltre che le query SQL restituiscono un insieme di colonne ben definito. Una query non può avere un numero variabile di colonne (a meno che non si utilizzi SQL dinamico attraverso una dichiarazione prepare).

+0

@Luv. . . Mie scuse. Non ho visto il collegamento SQLFiddle nella domanda. Il codice sopra è testato e funziona. –

+0

Perfetto funziona! Grazie per la risposta rapida e molto corretta! Lo accetterò come risposta è un po 'come il limite di tempo è finito: p –

-2

Ypu può utilizzare SQL dinamico, ma si dovrà utilizzare procedura

1

utilizzare questa query di elaborare il numero di colonne di valuta è necessario:

SELECT MAX(c) FROM 
((SELECT count(currency.name) AS c 
FROM country 
INNER JOIN countryCurrency ON country.country_id = countryCurrency.country_id 
INNER JOIN currency ON currency.currency_id = countryCurrency.currency_id 
GROUP BY country.name) as t) 

Poi creare dinamicamente ed eseguire prepared statement per generare il risultato, utilizzando la soluzione Gordon Linoff con il risultato della query sopra in questo thread.