2012-08-29 11 views
8

Mam tabelę z następującymi danymi:MySQL funkcje łańcuchowe

reservno || icode || location 
00004 || 00021 || Bohol - Cebu 
00004 || 00022 || Cebu - Manila 
00004 || 00014 || Manila - Bohol 

używam tej kwerendy do pobierania łączone wartość lokalizacji.

wynik
SELECT GROUP_CONCAT(location) from location_list where reservno='00004'; 

Kwerenda wygląda następująco:

GROUP_CONCAT(location) 
Bohol - Cebu,Cebu - Manila,Manila - Bohol 

Ale to, co chcę zrobić, to dla zapytania wyglądać tak: Bohol - Cebu - Manila - Bohol. Chciałbym scalić wynik w ten sposób. Jak mogę to osiągnąć? Nie jestem zaznajomiony z funkcjami ciągów MySQL, więc potrzebuję pomysłów, jak to zrobić. Każda pomoc zostanie doceniona. Wielkie dzięki!

+2

Jak określić kolejność zapisywania rekordów? – eggyal

Odpowiedz

6

Trzeba użyć SEPARATOR w GROUP_CONCAT funkcję:

SELECT GROUP_CONCAT(IF((@var_ctr := @var_ctr + 1) = @cnt, 
         location, 
         SUBSTRING_INDEX(location,' - ', 1) 
         ) 
         ORDER BY loc_id ASC 
         SEPARATOR ' - ') AS locations 

FROM location_list, 
    (SELECT @cnt := COUNT(1), @var_ctr := 0 
     FROM location_list 
     WHERE reservno='00004' 
    ) dummy 
WHERE reservno='00004'; 

Przykład: SQLFIDDLE

To nie jest dobra praktyka, aby przechowywać wiele wartości w tej samej kolumnie, Lepszy sposób mogą być:

reservno || icode || location_from || location_to 
00004 || 00021 || Bohol   || Cebu 
00004 || 00022 || Cebu   || Manila 
00004 || 00014 || Manila  || Bohol 
+0

Wow! To działało jak magia! Dziękuję bardzo! :)))) – xjshiya

+0

Nie ma za co! Twoje zdrowie! :) – Omesh

+2

@xjshiya Nie jest gwarantowane, że pojawi się w kolejności, którą chcesz. Powinieneś upewnić się, że określiłeś klauzulę 'order by'. –

3

Oto jeden sposób. Oddziela się dwie lokalizacje z pojedynczym location kolumnie distincts go, a następnie umieszcza go z powrotem razem SQL Fiddle:

SELECT GROUP_CONCAT(DISTINCT loc SEPARATOR ' - ') 
FROM 
(
    SELECT SUBSTRING_INDEX(location, ' - ', 1) AS loc 
    FROM location_list 
    WHERE reservno='00004' 
    UNION ALL 
    SELECT SUBSTRING_INDEX(location, ' - ', -1) AS loc 
    FROM location_list 
    WHERE reservno='00004' 
) separatedLocs 

może być patrząc na coś bardziej inteligentnego chociaż? Wyczuwam, że "lokalizacja" jest bardziej podobna do "od" do "rzeczy"? Podważam także decyzję o przechowywaniu więcej niż jednej wartości w kolumnie location. Znacznie lepiej byłoby przechowywać osobne kolumny location1 i location2.

+0

To przywraca: Bohol - Cebu - Manila. Czy jest jeszcze jakiś sposób, aby dodać Bohol na końcu? W ten sposób: Bohol - Cebu - Manila - Bohol? Dziękuję za odpowiedź! – xjshiya

+0

@xjshiya Jak określić kolejność, w jakiej powinny one być połączone? –

+0

co masz na myśli? – xjshiya

0

Jako the currently accepted answer wydaje się cause problems później, tutaj jest kolejna alternatywa. Jest silnie oparty na numerze the solution by lc., ale zajmuje się zamawianiem.

Po pierwsze: tabele SQL mają brak dobrze zdefiniowanej kolejności rzędu. Gdy wyszukujesz wszystkie wiersze tabeli, wiersze te będą zwracane w określonej kolejności, ale ta kolejność jest niezdefiniowana, może być powiązana z kolejnością dodawania wierszy i może się nieoczekiwanie zmieniać. Jeśli chcesz przetworzyć swoje wiersze w określonej kolejności, powinieneś dodać kolumnę, która będzie zawierała jakiś numer porządkowy lub smili. To jest powód, dla którego lc. kept bugging you o kolejności lokalizacji.

Jeśli masz taką kolumnę, zwany seq, a następnie można użyć następującego zapytania:

SELECT GROUP_CONCAT(loc SEPARATOR ' - ') 
FROM (
(SELECT 1 half, seq, SUBSTRING_INDEX(location, ' - ', 1) loc 
    FROM location_list 
    WHERE reservno='00004' 
    ORDER BY seq 
    LIMIT 1) 
UNION ALL 
(SELECT 2 half, seq, SUBSTRING_INDEX(location, ' - ', -1) loc 
    FROM location_list 
    WHERE reservno='00004') 
ORDER BY half, seq 
) locs 

Związek będzie produkować listę różnych miejscach, które są połączone w jeden ciąg znaków za pomocą peryferyjnych Wybierz. Pierwsza część związku daje pierwszą połowę pierwszej części trasy, podczas gdy druga część związku daje drugą połowę wszystkich części. Kolejność wyników unii jest do tej pory niezdefiniowana, więc potrzebujemy ogólnej reguły porządkowania. Potrzebujemy także reguły składania zamówień w pierwszej połowie, aby naprawdę wybrać pierwszą część trasy z klauzulą ​​limitu.

Here jest literą pikselową opartą na konfiguracji jednego Omesh.W przypadku braku kolumny seq używa ona kolumny icode do zamawiania rzeczy. Dlatego wynik różni się od tego, którego się spodziewałeś, i zamiast tego produkuje Manila - Bohol - Cebu - Manila.

Jeśli dodasz kolumnę seq, będziesz musiał zmienić schemat bazy danych, więc równie dobrze możesz go zmienić w taki sposób, aby dwa punkty końcowe każdej części zostały zamienione na dwie odrębne kolumny. Łączenie kolumn za pomocą CONCAT jest proste, ale ich rozdzielenie zwiększa złożoność zapytań zarówno dla programisty, jak i silnika bazy danych.

Jeśli nie możesz dodać kolumny sekwencji, ponieważ nie masz kontroli nad schematem bazy danych, masz kłopoty. Your comment here wskazuje, że zawsze szukasz cyklu, ale znalezienie takiego cyklu z nieuporządkowanych danych najlepiej wykonać przy użyciu map, który nie jest łatwo dostępny na poziomie SQL. Możesz to osiągnąć poprzez procedurę przechowywaną, jeśli musisz, wykonując jeden wybór dla każdej części jurysdykcji, ale wolałbym rozwiązać ten problem na poziomie aplikacji, gdybym był tobą.