sql >> Databasteknik >  >> RDS >> Mysql

SQL-fråga flera tabeller, med flera kopplingar och kolumnfält med kommaseparerad lista

Om du verkligen inte kan ändra tabellstrukturen är förmodligen det bästa du kan göra ett av de gamla listhackarna:

  • Använd en JOIN med 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 ;

  • Använd LIKE för att upptäcka närvaron av ett specifikt serviceID-värde i nodlistan

    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

Men som du redan har noterat borde kolumnen verkligen normaliseras. Även om metoderna ovan borde fungera för små datamängder, lider de av de vanliga problemen med att arbeta med "listor". Ingen av metoderna är särskilt indexvänlig och kommer som ett resultat inte att skala bra. Båda utför också strängjämförelser. Så den minsta skillnaden kan göra att matchningen misslyckas. Till exempel 1,4 skulle matcha två serviceID:n, medan 1,(space)4 eller 1,4.0 skulle bara matcha en.

Uppdatering baserat på kommentarer:

Vid andra läsningen är jag inte säker på att ovanstående svarar på den exakta frågan du ställer, men det borde ge en bra grund att arbeta med ...

Om du inte längre vill ha en CSV-lista använder du bara en av frågorna ovan och matar ut de enskilda frågekolumnerna som vanligt. Resultatet blir ett tjänstnamn per rad, dvs:

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

Annars, om du behöver bevara de kommaseparerade värdena, är en möjlighet att använda en <cfoutput group=".."> på frågeresultaten. Eftersom resultaten är sorterade efter "värd" först, ungefär som koden nedan. Obs! För att "grupp" ska fungera korrekt måste resultaten sorteras efter Host och du måste använda flera cfoutput taggar som visas nedan.

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

Resultatet ska se ut så här:

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, 


Uppdatering 2:

Jag glömde att det finns ett enklare alternativ till cfoutput group i 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>



  1. Hur man spelar in sekventiella samlingar av poster i MySQL

  2. Json kodar en hel mysql-resultatuppsättning

  3. Installera Oracle Instant-klienten i Docker-behållaren för Python cx_Oracle

  4. ORA-24550:signal mottagen:[si_signo=6] fel