【问题标题】:How do you merge rows from 2 SQL tables without duplicating rows?如何在不重复行的情况下合并 2 个 SQL 表中的行?
【发布时间】:2010-06-23 19:57:40
【问题描述】:

我想这个查询有点基础,我应该了解更多关于 SQL 的知识,但还没有对连接做太多事情,我想这是这里的解决方案。

我所拥有的是一张人员表格和一张他们担任的工作角色的表格。一个人可以有多项工作,我希望有一组结果,每人一行包含他们的详细信息和工作角色。

下面有两个示例表(people 和 job_roles),以便您更容易理解问题。

标识 |姓名 |电子邮件地址 |电话号码 1 |保罗 |保罗@example.com | 123456 2 |鲍勃 | bob@example.com | 567891 3 |巴特 | bart@example.com | 987561

工作角色

标识 |人名 |职称 |部门 1 | 1 |秘书 |小时 2 | 1 |助理 |媒体 3 | 2 |经理 |它 4 | 3 |财务员|金融 4 | 3 |经理 |它

这样我就可以像这样输出每个人和他们的角色

姓名:保罗 电子邮件地址:paul@example.com 电话:123456 工作角色: 人事部秘书 媒体部助理 _______ 姓名:鲍勃 电子邮件地址:bob@example.com 电话:567891 工作角色: IT部门经理

那么我将如何获取每个人的信息(来自 people 表)以及他们的工作详细信息(来自 job_roles 表),以像上面的示例一样输出。我想这将是某种方式将他们的工作和相关部门合并到一个可以拆分输出的工作列中,但也许有更好的方法,sql 会是什么样子?

谢谢

保罗

PS 如果这有什么不同,那将是一个 mySQL 数据库

【问题讨论】:

    标签: sql mysql join database rows


    【解决方案1】:

    它看起来像一个直接的连接:

    SELECT p.*, j.*
      FROM People AS p INNER JOIN Roles AS r ON p.id = r.person_id
     ORDER BY p.name;
    

    剩下的工作是格式化;最好通过报告包来完成。


    感谢您的快速回复,这似乎是一个好的开始,但您会得到每个人的多行数据(您必须想象这是一个表格,因为您似乎无法在 cmets 中进行格式化):

    id | Name | email_address    | phone_number | job_role  | department
     1 | paul | paul@example.com | 123456       | secretary | HR
     1 | paul | paul@example.com | 123456       | assistant | media
     2 | bob  | bob@example.com  | 567891       | manager   | IT
    

    如果可能的话,我希望每人一排,最好包含他们所有的工作角色?

    这取决于您的 DBMS,但大多数可用的不支持 RVA - 关系值属性。您想要的是结果中的工作角色和部门部分,例如与用户关联的表:

    +----+------+------------------+--------------+------------------------+
    | id | Name | email_address    | phone_number |   dept_role            |
    +----+------+------------------+--------------+------------------------+
    |    |      |                  |              | +--------------------+ |
    |    |      |                  |              | | job_role   | dept  | |
    |  1 | paul | paul@example.com | 123456       | | secretary  | HR    | |
    |    |      |                  |              | | assistant  | media | |
    |    |      |                  |              | +--------------------+ |
    +----+------+------------------+--------------+------------------------+
    |    |      |                  |              | +--------------------+ |
    |    |      |                  |              | | job_role   | dept  | |
    |  2 | bob  | bob@example.com  | 567891       | | manager    | IT    | |
    |    |      |                  |              | +--------------------+ |
    +----+------+------------------+--------------+------------------------+
    

    这准确地代表了您想要的信息,但通常不是一个选项。

    因此,接下来会发生什么取决于您的报告生成工具。使用我最熟悉的那个(Informix ACE,Informix SQL 的一部分,可从 IBM 与 Informix DBMS 一起使用),您只需确保对数据进行排序,然后打印姓名、电子邮件地址和电话号码在报告的 'BEFORE GROUP OF id' 部分中,以及在 'ON EVERY ROW' 部分中,您将只处理(打印)角色和部门信息。

    将报表格式与数据检索操作分开通常是个好主意;这是一个必要的示例,除非您的 DBMS 具有帮助格式化所选数据的特殊功能。


    天哪,这听起来很复杂,而且我不能在 PHP 页面中的 mySQL 数据库上轻松运行?

    RVA 的东西 - 你是对的,这不适用于 MySQL 和 PHP。

    另一方面,有数以百万计的报告(即为呈现给用户而格式化的查询结果)大致执行此操作。他们的技术术语是'Control-Break Report',但基本思想并不难。

    您保留上次处理的“id”编号的记录 - 您可以将其初始化为 -1 或 0。 当当前记录的 id 号码与之前的号码不同时,您就有了一个新用户,您需要为新用户启动一组新的输出行并打印姓名、电子邮件地址和电话号码(并更改最后一个已处理的 ID 号)。当当前记录具有相同的 ID 号时,您所要做的就是处理工作角色和部门信息(而不是姓名、电子邮件地址和电话号码)。当 ID 号更改时,会发生“中断”。使用单级控制中断,并不难;如果你有 4 或 5 个级别,你必须做更多的工作,这就是为什么有报告包来处理它的原因。

    所以,这并不难 - 只是需要一点小心。

    【讨论】:

    • +1:打败我,所以我会添加(这个关于视觉表示 JOIN 的链接)[codinghorror.com/blog/2007/10/…
    • 感谢您的快速回复,这似乎是一个好的开始,但您每个人都会得到多行(您必须想象这是一张表格,因为您似乎无法在 cmets 中进行格式化) : 编号 |姓名 |电子邮件地址 |电话号码 |工作角色 |部门 1 |保罗 |保罗@example.com | 123456 |秘书 |人力资源 1 |保罗 |保罗@example.com | 123456 |助理 |媒体 2 |鲍勃 | bob@example.com | 567891 |经理 |如果可能的话,我希望每人一排,并在其中包含他们所有的工作角色?
    • 天哪,这听起来很复杂,而且我不能在 PHP 页面中的 mySQL 数据库上轻松运行?
    • 感谢您提供的信息,它非常有用,我按照 Martin Smith 的建议将您的一些想法与 group_concat 一起使用。
    【解决方案2】:

    回复:

    我希望 SQL 可以做一些事情 聪明地把行连在一起 很好,所以我基本上有一份工作 包含该人工作的列。

    你可以很接近

    SELECT  p.id, p.name, p.email_address, p.phone_number,
    group_concat(concat(job_title, ' for ', department, ' department')  SEPARATOR '\n') AS JobRoles
    FROM People AS p 
        INNER JOIN job_roles AS r ON p.id = r.person_id
    GROUP BY p.id, p.name, p.email_address, p.phone_number
     ORDER BY p.name;
    

    【讨论】:

    • 这是非常聪明和容易知道的,尽管我仍然更喜欢在 PHP 中进行普通连接和格式化数据。如果有一天您想更改格式(例如,在工作角色之间添加
      ),则必须修改 SQL 查询。 GROUP_CONCAT 消除了数据库逻辑和表示的分离。这也使单元测试变得更加困难。
    【解决方案3】:

    按照您想要的方式进行操作意味着结果集数组可能有无限的列,这将非常混乱。例如,您可以离开加入工作表 10 次并获得工作 1、工作 2、..工作 10。

    我会做一个单一的连接,然后使用 PHP 检查名称 ID 从 1 行到下一行是否相同。

    【讨论】:

    • 谢谢,这就是我得出的结论,但希望 SQL 可以做一些聪明的事情并将行很好地连接在一起,所以我基本上有一个工作列,其中包含该人员的工作。
    【解决方案4】:

    一种方法可能是左外连接表,然后使用将它们加载到数组中

    $people_array =array(); 
    while($row1=mysql_fetch_assoc($extract1)){ 
    $people_array[] = $row1;  
    } 
    

    然后循环使用

     for ($x=0;$x<=sizeof($people_array;) 
        {  
    echo $people_array[$x][id]; 
    echo $people_array[$x][name]; 
    
    for($y=0;$y<=$number_of_roles;$y++) 
    { 
     echo $people_array[$x][email_address]; 
     echo $people_array[$x][phone_number]; 
        $x++; 
    } 
         } 
    

    您可能需要稍微处理一下查询和循环,但它通常应该做您想做的事情。要像上面那样工作,每个人都必须拥有相同数量的角色,但您可能能够填补在你的表格中的空白处

    【讨论】:

    • 好主意,但组 concat 似乎是一个更清洁的解决方案。
    猜你喜欢
    • 2017-04-30
    • 1970-01-01
    • 2016-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多