当前位置: 首页 > 面试题库 >

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

连坚白
2023-03-14
问题内容

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

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

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.serviceIDservice.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列表但又不能同时扩展两个人的人。

这很接近:使用以逗号分隔sql的id,但使用的不是完全相同。

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

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

这是我第一次在stackoverflow上发帖,所以我很抱歉,如果真的有答案,我没有搜索足够长的时间,因此这个问题会重复出现。

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

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

因此,我得到以下信息:

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

在这一点上,我不确定CFML或SQL查询中的内容是否只是一点点更改。但是,它看起来确实很有希望。


问题答案:

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

  • 使用JOIN与FIND_IN_SET(值,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检测节点列表中的特定服务ID值的存在

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="..">查询结果使用a
。由于结果首先由“主机”排序,因此类似于下面的代码。 注意:
要使“组”正常工作,必须按以下顺序对结果进行排序,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>


 类似资料:
  • 问题内容: 我有看起来像这样的数据: 对于每个customer_id,我需要用逗号分隔的列表,以指示该客户运营的月份: 等等。如何使用SQL Server 2005 SQL(而不是T-SQL)轻松生成此逗号分隔的列表? 我在Stack Overflow和其他地方在这里看到的大多数解决方案似乎都是基于联接多个行值而不是列值来创建逗号分隔的列表: T-SQL FOR XML路径(’‘) 关联的子查询与

  • 问题内容: 这是我的表结构: 我需要拆分该列,并希望通过一个简单的sql查询来做到这一点,因为我不知道如何使用函数,并且希望将其保持简单。 这是我已经发现的: 但这仅输出 有没有一种方法来拆分一切从到,,等? 提前致谢。 问题答案:

  • 问题内容: 我有两个表,和。 在表中我有一列。该列由电影适合的类别组成。这些类别是用逗号分隔的ID。 这是一个例子: 现在是一个实际的问题:是否可以执行一个查询,从电影表中排除类别列,而是从类别表中选择匹配的类别并以数组形式返回它们?像联接一样,但问题是存在多个用逗号分隔的类别,是否可以进行某种正则表达式? 问题答案: 在数据库字段中使用逗号分隔的列表是一种反模式,应不惜一切代价避免使用。 因为在

  • 问题内容: 我有以下问题。我想加入两个表。 第一个表具有如下条目: 第二个表是这样构建的: 我的结果应显示以下内容 我只是不知道如何解决这个问题。 仅使用sql selects可能需要此功能吗? 亲切的问候 问题答案: 并不是那么困难,但是-就像你被告知的那样,你宁愿不要那样做。

  • 问题内容: 所以我有四个桌子。每个表都有一个与前一个表ID相同的ID。因此,我的点击表中有一个ID和一个广告来源的ID。在广告表中,它有一个广告ID和一个来自其广告系列的ID。所以这是一个例子。 因此,要找出表4中的值从何而来,我需要遍历每个表并检查它们具有哪个ID。基本上,我想知道表1中的哪些值与表4中的值相关联。 表4中的内容是网站的访问者,表1中的内容是互联网广告。我想知道哪些访客来自哪些广

  • 问题内容: 我有一个未标准化的表,其中的列包含逗号分隔的列表,该列表是另一个表的外键: 我想将此数据读入不提供过程语言的搜索引擎中。 那么,有没有一种方法, 要么 就这一栏中加入 或 该数据运行查询插入相应的条目到一个新的表?结果数据应如下所示: 如果DBMS支持返回表的函数,但MySQL显然不支持,我可以想到一个解决方案。 问题答案: 在MySQL中,可以通过以下方式实现 现在要获取逗号分隔的v