2013-07-24 18 views
6

Szukałem dużo, ale nie znalazłem właściwego rozwiązania mojego problemu.SQL GROUP_CONCAT podzielone na różne kolumny

Co chcę zrobić?

Mam 2 tabele w MySQL: - Kraj - waluta (łączę je ze sobą za pośrednictwem CountryCurrency -> ze względu na wiele do wielu relacji)

Zobacz to na przykładzie pracy: http://sqlfiddle.com/#!2/317d3/8/0

Chcę połączyć obie tabele przy użyciu łączenia, ale chcę wyświetlić tylko jeden wiersz dla każdego kraju (niektóre kraje mają wiele walut, więc był to pierwszy problem).

Znalazłem funkcję 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 

ten ma następujący wynik:

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 

Ale to, co chcę teraz podzielić walutach, w różnych kolumn (waluta 1 walutami 2, ...). Próbowałem już funkcji takich jak MAKE_SET(), ale to nie działa.

+0

SQL nie obsługuje dynamicznej liczby kolumn. Będziesz musiał to zrobić w aplikacji. – Vatev

+0

Możesz użyć logiki w Kursorze, aby to zrobić. Ale kursor najpierw musiałby sprawdzić, ile kolumn danych wymaga zestaw wyników. Dynamicznie utwórz tabelę tymczasową, która zostanie wypełniona, a następnie wybrana. Numerem dynaminc jest problem z tym wyzwaniem. –

Odpowiedz

6

Możesz to zrobić pod numerem substring_index(). Poniższe zapytanie wykorzystuje je jako podzapytania, a następnie zastosowanie tej logiki:

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 

Wyrażenie substring_index(currencies, ',' 2) zaczyna listę w walutach aż do drugiego. Dla amerykańskiego Somoa byłby to 'US Dollar,Kwanza'. Następne wywołanie z -1 jako argumentem przyjmuje ostatni element listy, który byłby 'Kwanza', który jest drugim elementem currencies.

Należy również zauważyć, że zapytania SQL zwracają dobrze zdefiniowany zestaw kolumn. Zapytanie nie może mieć zmiennej liczby kolumn (chyba że używasz dynamicznego SQL przez instrukcję prepare).

+0

@ Luv. . . Przepraszam. Nie widziałem linku SQLFiddle w pytaniu. Powyższy kod jest testowany i działa. –

+0

Perfect it works! Dzięki za szybką i bardzo poprawną odpowiedź! Przyjmuję to jako odpowiedź, jako że czas upłynął: s –

-2

ypu można użyć dynamicznego SQL, ale trzeba będzie procedurę

1

użyć tej kwerendy użyć wypracować liczbę kolumn walutowych trzeba:

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) 

Następnie dynamicznie tworzyć i wykonywać prepared statement wygenerować wynik, używając rozwiązania Gordon Linoff z wynikiem zapytania powyżej w tym wątku.