2012-08-29 8 views
8

que tienen una una tabla con los siguientes datos:funciones de cadena de MySQL

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

puedo utilizar esta consulta para recuperar el valor concatenado de ubicación.

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

La consulta es el siguiente:

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

Pero lo que yo quiero hacer es para que la consulta se parece a esto: Bohol - Cebu - Manila - Bohol. Me gustaría fusionar el resultado así. ¿Cómo puedo conseguir esto? No estoy tan familiarizado con las funciones de cadenas de MySQL, así que necesito algunas ideas sobre cómo hacer que esto funcione. Cualquier ayuda será apreciada. ¡Muchas gracias!

+2

¿Cómo se determina el orden en que se deben unir los registros? – eggyal

Respuesta

6

Es necesario utilizar SEPARATOR en GROUP_CONCAT función:

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'; 

Ejemplo: SQLFIDDLE

No es una buena práctica para almacenar varios valores en la misma columna, mejor forma podría ser:

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

¡Guau! ¡Esto funcionó como una magia! Muchas gracias! :)))) – xjshiya

+0

¡De nada! ¡Aclamaciones! :) – Omesh

+2

@xjshiya Sin embargo, no está garantizado que esto saldrá en el orden que necesariamente deseas. Debe asegurarse de especificar una cláusula 'order by'. –

3

Aquí hay una manera. Que separa las dos poblaciones de su sola columna location, distincts que, a continuación, pone de nuevo juntos 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 

Usted podría estar buscando algo más inteligente, aunque? ¿Siento que "ubicación" es más como un tipo de cosas "de a"? También cuestiono la decisión de almacenar más de un valor en su columna location de esta manera. Sería mucho mejor que almacenaras un location1 y location2 como columnas separadas.

+0

Reconstruye: Bohol - Cebu - Manila. ¿Hay alguna forma de agregar Bohol en la última parte? De esta manera: Bohol - Cebu - Manila - Bohol? ¡Gracias por la respuesta! – xjshiya

+0

@xjshiya ¿Cómo se determina el orden en el que deberían unirse entonces? –

+0

¿qué quieres decir? – xjshiya

0

Como the currently accepted answer parece cause problems más adelante, aquí hay otra alternativa. Se basa en gran medida en the solution by lc., pero se encarga de ordenar.

En primer lugar, las tablas de SQL tienen sin orden de fila bien definida. Cuando consulta todas las filas de una tabla, esas filas se devolverán en un orden determinado, pero esa orden no está definida, puede estar o no relacionada con el orden en que se agregaron las filas y puede cambiar inesperadamente. Entonces, cuando desee procesar sus filas en un orden determinado, debe agregar una columna para contener algún tipo de número de secuencia o smilar. Esa es la razón por la cual lc. kept bugging you sobre el orden de las ubicaciones.

Si tiene una columna de este tipo, llamado seq, a continuación, puede utilizar la siguiente consulta:

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 

La unión producirá una lista de los distintos lugares, que se combina en una sola cadena utilizando la más externa seleccionar. La primera parte de la unión produce la primera mitad de la primera parte de la ruta, mientras que la segunda parte de la unión le dará la segunda mitad de todas las partes. El orden del resultado de la unión no está definido hasta el momento, por lo que necesitamos una regla general de ordenamiento. También necesitamos una regla de pedido para la primera mitad, de modo que realmente elijamos la primera parte de la ruta con la cláusula de límite.

Here es un sqlfiddle basado en la configuración de Omesh.A falta de una columna seq, usa la columna icode para pedir cosas. Por lo tanto, el resultado difiere del que esperaba y, en su lugar, produce Manila - Bohol - Cebu - Manila.

Si agrega una columna seq, tendrá que cambiar el esquema de la base de datos, por lo que también puede cambiarlo de forma que los dos extremos de cada parte se conviertan en dos columnas distintas. Combinar columnas usando CONCAT es simple, pero dividirlas aumenta la complejidad de las consultas tanto para el desarrollador como para el motor de la base de datos.

Si no puede agregar una columna de secuencia, porque no tiene control sobre el esquema de la base de datos, entonces tiene problemas. Your comment here indica que siempre está buscando un ciclo, pero encontrar dicho ciclo a partir de datos desordenados se hace mejor usando un map, que no está disponible en el nivel de SQL. Podrías lograr esto a través de un procedimiento almacenado si es necesario, ejecutando uno para cada parte del jurney, pero prefiero abordar esto a nivel de aplicación si fuera tú.

Cuestiones relacionadas