【问题标题】:SQL query multiple tables, with multiple joins and column field with comma separated listSQL查询多个表,具有多个连接和逗号分隔列表的列字段
【发布时间】:2014-10-15 18:11:03
【问题描述】:

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

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

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 查询中的一些变化。但是,它看起来确实很有希望。

【问题讨论】:

  • +1 希望所有第一次提出的问题都经过深思熟虑。在您的结果中...您是在寻找为每个服务名称单独设置一行的服务,还是希望保留逗号分隔的值?
  • 我应该指定的!好问题!老实说,考虑到当前的布局,我可以不用逗号。我会很高兴每行一个不带逗号。
  • @Grimdari - 如果您不再需要 csv 列表,只需使用以下查询之一并照常输出各个查询列。
  • 即不需要<cfoutput group="...">
  • 很高兴我能帮上忙。对于像这样的小数据集,性能应该没问题(带有注意事项)。我只是不会在 3000 万行表上推荐它;-)

标签: mysql sql arrays join coldfusion


【解决方案1】:

如果你真的不能修改表结构,你能做的最好的可能是旧的列表黑客之一:

  • 使用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 将仅匹配一个。

基于 cmets 的更新:

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

如果您不再需要 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:

我忘了在 MySQL 中有一个更简单的替代 cfoutput groupGROUP_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>

【讨论】:

  • 我现在将您的建议插入我的 SQL 和 CFML。我会把我的结果发回来!谢谢!
  • 为了完整起见,我更新了答案以包含一个更简单的选项来生成 csv 列表 ;-)
  • 您的 Update2 将 7233 条记录的查询缩短了大约 4 毫秒。我仔细检查了它是否没有被缓存并且仍然剃掉了 4 毫秒。 :D Group_Concat 似乎对这种类型的查询更有效。
  • (编辑。该死的 5 分钟限制...)我想这是有道理的,因为 group_concat 总体上返回的数据略少(即减去重复的主机和控件名称)。另外,输出可能会快一点,因为您只需要一个普通的 cfoutput 而不是分组的。可能差别不大,但值得注意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多