sql >> Database teknologi >  >> RDS >> Mysql

SQL-forespørgsel efter flere tabeller med flere joinforbindelser og kolonnefelt med kommasepareret liste

Hvis du virkelig ikke kan ændre tabelstrukturen, er det sandsynligvis det bedste du kan gøre et af de gamle listehack:

  • Brug en JOIN med FIND_IN_SET(værdi, kommaSepareret streng)

    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 ;

  • Brug LIKE for at detektere tilstedeværelsen af ​​en specifik serviceID-værdi i nodelisten

    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 allerede har bemærket, burde kolonnen virkelig normaliseres. Selvom metoderne ovenfor burde fungere for små datasæt, lider de af de sædvanlige problemer med at arbejde med "lister". Ingen af ​​metoderne er meget indeksvenlige og vil som et resultat ikke skalere godt. Begge udfører også strengsammenligninger. Så den mindste forskel kan få matchningen til at mislykkes. For eksempel 1,4 ville matche to serviceID'er, hvorimod 1,(space)4 eller 1,4.0 ville kun matche én.

Opdatering baseret på kommentarer:

Ved anden læsning er jeg ikke sikker på, at ovenstående besvarer det præcise spørgsmål, du stiller, men det burde give et godt grundlag at arbejde med ...

Hvis du ikke længere ønsker en CSV-liste, skal du blot bruge en af ​​forespørgslerne ovenfor og udskrive de enkelte forespørgselskolonner som normalt. Resultatet vil være ét servicenavn pr. række, dvs.:

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

Ellers, hvis du har brug for at bevare de kommaseparerede værdier, er en mulighed at bruge en <cfoutput group=".."> på forespørgselsresultaterne. Da resultaterne er sorteret efter "Vært" først, noget som koden nedenfor. NB: For at "gruppe" kan fungere korrekt, skal resultaterne sorteres efter Host og du skal bruge flere cfoutput tags som vist nedenfor.

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

Resultatet skulle se sådan ud:

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,


Opdatering 2:

Jeg glemte, at der er et enklere alternativ til 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. MYSQL REGEXP søgning i JSON-streng

  2. Hvordan virker underforespørgsel i select statement i oracle

  3. Importer shapefiler i postgresql i linux ved hjælp af pgadmin 4

  4. 4 måder at finde duplikerede rækker i MySQL