sql >> Databáze >  >> RDS >> Mysql

SQL dotaz na více tabulek, s více spojeními a sloupcovým polem se seznamem odděleným čárkami

Pokud opravdu nemůžete upravit strukturu tabulky, pravděpodobně nejlepší, co můžete udělat, je jeden ze starých hacků seznamů:

  • Použijte JOIN s FIND_IN_SET(hodnota, čárkaSeparatedString)

    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 ;

  • Použijte LIKE k detekci přítomnosti konkrétní hodnoty serviceID v seznamu uzlů

    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

Jak jste však již poznamenali, sloupec by skutečně měl být normalizován. Zatímco výše uvedené metody by měly fungovat pro malé soubory dat, trpí obvyklými problémy práce se „seznamy“. Ani jedna metoda není příliš přátelská k indexům a v důsledku toho se nebude dobře škálovat. Oba také provádějí porovnávání řetězců. Takže sebemenší rozdíl může způsobit selhání párování. Například 1,4 by odpovídalo dvěma serviceID, zatímco 1,(space)4 nebo 1,4.0 odpovídá pouze jednomu.

Aktualizace na základě komentářů:

Při druhém přečtení si nejsem jistý, že výše uvedené odpovědi přesně odpovídají na otázku, na kterou se ptáte, ale mělo by to poskytnout dobrý základ pro práci s ...

Pokud již nechcete seznam CSV, stačí použít jeden z výše uvedených dotazů a vypsat jednotlivé sloupce dotazů jako obvykle. Výsledkem bude jeden název služby na řádek, tj.:

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

V opačném případě, pokud potřebujete zachovat hodnoty oddělené čárkami, jednou z možností je použít <cfoutput group=".."> na výsledky dotazu. Vzhledem k tomu, že výsledky jsou nejprve seřazeny podle "hostitele", něco jako kód níže. Poznámka: Aby "skupina" fungovala správně, musí být výsledky seřazeny podle Host a musíte použít více cfoutput značky, jak je uvedeno níže.

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

Výsledek by měl vypadat takto:

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, 


Aktualizace 2:

Zapomněl jsem, že existuje jednodušší alternativa k cfoutput group v 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 sum() pro různé řádky

  2. SQL Server *=Operátor?

  3. Výstup mezi dvěma daty mysql

  4. Připojení Pythonu k databázi MySQL pomocí konektoru MySQL a příkladu PyMySQL