sql >> Base de Datos >  >> RDS >> Mysql

SQL consulta múltiples tablas, con múltiples uniones y campo de columna con lista separada por comas

Si realmente no puede modificar la estructura de la tabla, probablemente lo mejor que puede hacer es uno de los trucos de la lista anterior:

  • Usa un JOIN con FIND_IN_SET(value, commaSeparatedString)

    SELECT n.Host, c.Name AS ControlName, s.Name AS ServiceName FROM node n LEFT JOIN control c ON c.controlID = n.controlID LEFT JOIN service s ON FIND_IN_SET(s.serviceID, n.serviceId) ORDER BY n.host, s.Name ;

  • Usa LIKE para detectar la presencia de un valor de ID de servicio específico dentro de la lista de nodos

    SELECT n.Host, c.Name AS ControlName, s.Name AS ServiceName FROM node n LEFT JOIN control c ON c.controlID = n.controlID LEFT JOIN service s ON CONCAT(',', n.serviceID,',') LIKE CONCAT('%,', s.serviceID,',%') ORDER BY n.host, s.Name ;

SQLFiddle

Sin embargo, como ya notó, esa columna realmente debería normalizarse. Si bien los métodos anteriores deberían funcionar para conjuntos de datos pequeños, sufren los problemas habituales de trabajar con "listas". Ninguno de los métodos es muy compatible con los índices y, como resultado, no se escalará bien. Además, ambos realizan comparaciones de cadenas. Entonces, la más mínima diferencia puede hacer que la coincidencia falle. Por ejemplo, 1,4 coincidiría con dos ID de servicio, mientras que 1,(space)4 o 1,4.0 coincidiría solo con uno.

Actualización basada en comentarios:

En la segunda lectura, no estoy seguro de que lo anterior responda la pregunta precisa que está haciendo, pero debería proporcionar una buena base para trabajar con...

Si ya no desea una lista CSV, simplemente use una de las consultas anteriores y genere las columnas de consulta individuales como de costumbre. El resultado será un nombre de servicio por fila, es decir:

   server1 | Control Name One | Service Name 200
   server1 | Control Name One | Service Name 50
   ..

De lo contrario, si necesita conservar los valores separados por comas, una posibilidad es usar un <cfoutput group=".."> sobre los resultados de la consulta. Dado que los resultados se ordenan primero por "Host", algo como el código a continuación. Nota: Para que "grupo" funcione correctamente, los resultados deben ordenarse por Host y debe usar múltiples cfoutput etiquetas como se muestra a continuación.

 <cfoutput query="..." group="Host"> 
    #Host# |
    #ControlName# |
    <cfoutput>
      #ServiceName#,
    </cfoutput>
    <br>
 </cfoutput>

El resultado debería verse así:

server1 | Control Name One | Service Name 200, Service Name 50, Service Name Four, Service Name One, Service Name Three, Service Name Two, 
server2 | Control Name Two | Service Name 200, Service Name Four, Service Name Three, Service Name Two, 
server3 | Control Name Two | Service Name 200, Service Name 50, Service Name Four, Service Name One, Service Name Three, Service Name Two, 
server4 | Control Name Three | Service Name 200, Service Name 50, Service Name One, Service Name Two, 
server5 | Control Name Three | Service Name Four, Service Name One, 


Actualización 2:

Olvidé que hay una alternativa más simple a cfoutput group en MySQL:GROUP_CONCAT

<cfquery name="qry" datasource="MySQL5">
   SELECT n.Host, c.Name AS ControlName, GROUP_CONCAT(s.Name) AS ServiceNameList 
   FROM node n 
        LEFT JOIN control c ON c.controlID = n.controlID 
        LEFT JOIN service s ON FIND_IN_SET(s.serviceID, n.serviceId) 
   GROUP BY n.Host, c.Name
   ORDER BY n.host
</cfquery>