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łówSELECT 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 ;
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>