Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Zapytanie SQL wielu tabel, z wieloma sprzężeniami i polem kolumny z listą oddzieloną przecinkami

Jeśli naprawdę nie możesz modyfikować struktury tabeli, prawdopodobnie najlepszym, co możesz zrobić, jest jeden ze starych hacków dotyczących list:

  • Użyj JOIN z ZNAJDŹ_IN_SET(wartość, 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 ;

  • Użyj LIKE aby wykryć obecność określonej wartości ServiceID na liście węzłów

    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

Jednak, jak już zauważyłeś, kolumna naprawdę powinna być znormalizowana. Chociaż powyższe metody powinny działać w przypadku małych zestawów danych, cierpią one z powodu zwykłych problemów związanych z pracą z „listami”. Żadna z metod nie jest bardzo przyjazna dla indeksów iw rezultacie nie będzie się dobrze skalować. Ponadto oba wykonują porównania ciągów. Tak więc najmniejsza różnica może spowodować niepowodzenie dopasowania. Na przykład 1,4 pasowałby do dwóch identyfikatorów usługi, podczas gdy 1,(space)4 lub 1,4.0 pasowałby tylko do jednego.

Aktualizacja na podstawie komentarzy:

Przy drugim czytaniu nie jestem pewien, czy powyższe odpowiada na dokładne pytanie, które zadajesz, ale powinno to stanowić dobrą podstawę do pracy z ...

Jeśli nie potrzebujesz już listy CSV, po prostu użyj jednego z powyższych zapytań i wypisz poszczególne kolumny zapytań jak zwykle. Wynikiem będzie jedna nazwa usługi w wierszu, tj.:

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

W przeciwnym razie, jeśli chcesz zachować wartości oddzielone przecinkami, jedną z możliwości jest użycie <cfoutput group=".."> w wynikach zapytania. Ponieważ wyniki są uporządkowane najpierw według „hosta”, coś takiego jak poniższy kod. Uwaga: Aby "grupa" działała poprawnie, wyniki muszą być uporządkowane przez Host i musisz użyć wielu cfoutput tagi, jak pokazano poniżej.

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

Wynik powinien wyglądać tak:

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, 


Aktualizacja 2:

Zapomniałem, że istnieje prostsza alternatywa dla cfoutput group w 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wersjonowanie wierszy w MySQL

  2. Jak wstawić wiele wierszy na podstawie zapytania?

  3. prawidłowy sposób wstawiania danych o id jako auto-inkrementacji w mysqli

  4. Przykładowy skrypt php do paginacji

  5. Umieszczenie Railsów nad istniejącą bazą danych