mysql - SQL 查询多个表,具有多个联接和带有逗号分隔列表的列字段

标签 mysql sql arrays join coldfusion

我有一个查询,其中连接了三个单独的表(节点、控制、服务)。

下面是他们的列标题和示例数据。

NODE TABLE  (contains over 7000 rows)
nodeID | host    | serviceID        | controlID
     1 | server1 | 1,2,3,4,9,50,200 |         1
     2 | server2 | 2,3,4,9,200      |         2
     3 | server3 | 1,2,3,4,9,50,200 |         2
     4 | server4 | 1,2,50,200       |         3
     5 | server5 | 1,4              |         3

CONTROL TABLE  (contains roughly 50 rows)
controlID | name
        1 | Control Name One
        2 | Control Name Two
        3 | Control Name Three
        4 | Control Name Four
        5 | Control Name Five

SERVICE TABLE (contains roughly 3000 rows)
serviceID | name
        1 | Service Name One
        2 | Service Name Two
        3 | Service Name Three
        4 | Service Name Four
        5 | Service Name Five
        6 | Service Name Six
       50 | Service Name 50
      200 | Service Name 200

如您所见,除了 node.serviceID 列之外,数据库表进行了一些规范化。我完全同意 node.serviceID 应该规范化并创建一对多的数据透视表。没有争论。但是,我不控制将信息插入数据库的脚本。我只能从表格中读取数据并尽可能格式化数据。

因此,下面是我编写的 SQL 查询,它确实有效,但正如预期的那样,node.serviceID 没有与 service.serviceID 很好地连接。请注意,我在最终查询中没有使用 SELECT *,我从节点表中选择了大约 20 个字段,并且不希望使查询更加困惑。下面只是一个例子。

SELECT *
FROM node AS a
LEFT JOIN control AS b ON a.controlID = b.controlid
LEFT JOIN service AS c ON a.serviceID = c.serviceId
ORDER BY a.host

上面的查询会输出类似的内容:

Host      Control              Services
server1   Control Name One     1,2,3,4,9,50
server2   Control Name Three   1,2,9,50
server3   Control Name Two     4
server4   Control Name Four    1,2,3,4,9
server5   Control Name Two     1,2,3,50
server6   Control Name Five    1,3,4,9,50

我正在寻找的是:

Host      Control              Services
server1   Control Name One     Service Name One,
                               Service Name Two,
                               Service Name Three,
                               Service Name Four,
                               Service Name Nine,
                               Service Name Fifty
server2   Control Name Three   Service Name One,
                               Service Name Two,
                               Service Name Nine,
                               Service Name Fifty
server3   Control Name Two     Service Name Four
server4   Control Name Four    Service Name One,
                               Service Name Two,
                               Service Name Three,
                               Service Name Four,
                               Service Name Nine

我在 stackoverflow.com 上搜索了遇到此类问题的人,但我只能找到在 ID 和名称上连接多个表的人,或者有人扩展 ID 列表的人,但不能同时找到两者。

这个很接近:Using id that are comma separated sql但不完全是。

我已经尝试了使用 ListToArray() 的 CFML 的各种方法,并尝试使用索引循环它们,但对我来说没有任何效果。

我获取数据的服务器是 MySQL 5.1,我使用 jQuery 和 ColdFusion (Railo 4.2) 的组合来格式化数据。

这是我第一次在 stackoverflow 上发帖,所以如果真的有答案,我很抱歉,我搜索的时间不够长,并且会使这个问题重复。

-----------------更新--------------------

我尝试了 Leigh 建议的查询和 CFML。

所以,我得到以下信息:

server1 服务名称一、服务名称一、服务名称一、服务名称一、服务名称一、服务名称一、服务名称一、服务名称二、服务名称二、服务名称二、服务名称二、服务名称二、服务名称二、服务名称三、服务名称四、服务名称四、服务名称四、服务名称四、服务名称四、服务名称四、服务名称四

此时我不确定这是否只是 CFML 或 SQL 查询中的某些内容的一点变化。但是,它看起来确实很有希望。

最佳答案

如果您确实无法修改表结构,可能您能做的最好的事情就是使用旧的列表技巧之一:

  • 使用JOINFIND_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 ;

  • 使用LIKE检测节点列表中是否存在特定的 serviceID 值

    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

但是,正如您已经指出的那样,该列确实应该标准化。虽然上述方法应该适用于小型数据集,但它们会遇到使用“列表”时常见的问题。这两种方法都对索引不太友好,因此无法很好地扩展。此外,两者都执行字符串比较。所以最细微的差别都可能导致匹配失败。例如,1,4将匹配两个 serviceID,而 1,(space)41,4.0只会匹配一个。

根据评论更新:

在第二次阅读时,我不确定上面的内容是否准确回答了您所提出的问题,但它应该为与...合作提供良好的基础

如果您不再需要 CSV 列表,只需使用上面的查询之一并照常输出各个查询列。结果将是每行一个服务名称,即:

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

否则,如果您需要保留逗号分隔值,一种可能是使用 <cfoutput group="..">关于查询结果。由于结果首先按“主机”排序,因此类似于下面的代码。 注意:为了使“组”正常工作,结果必须按 Host 排序。并且您必须使用多个 cfoutput标签如下所示。

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

结果应如下所示:

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, 


更新2:

我忘记了 cfoutput group 有一个更简单的替代方案在 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>

关于mysql - SQL 查询多个表,具有多个联接和带有逗号分隔列表的列字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43837774/

相关文章:

mysql - 如何将列名组合到 MySQL "LIKE"子句中

mysql - 按顺序选择Mysql条件组的问题

mysql - 导入 .csv 并转换为 mysql 中的日期

SQL Server,从不同表的 2 列中选择

java - 数组 : if (data[a]. 的增强循环包含 ("word")) 问题:类型不兼容

php - 如何根据条件向数组添加一些项目?

java - 无法连接到 MS Access 数据库

mysql - 组合三个 SQL 查询

c - 在 C 中通过引用传递结构,但修改并非全部存在

c++ - 检查二维数组的所有元素是否相等的最快方法