【问题标题】:How to get multiple records against one record based on relation?如何根据关系针对一条记录获取多条记录?
【发布时间】:2010-09-11 06:23:45
【问题描述】:

我有两个表组织和员工具有一对多关系,即一个组织可以有多个员工。现在我想选择特定组织的所有信息以及该组织所有员工的名字。最好的方法是什么?我可以在单个记录集中获得所有这些,否则我将不得不根据否获得多行。员工?这是我想要的一些图形演示:

Org_ID      Org_Address    Org_OtherDetails    Employess

1           132A B Road    List of details     Emp1, Emp2, Emp3.....

【问题讨论】:

    标签: mysql sql database


    【解决方案1】:

    最初的问题是特定于数据库的,但也许这是一个包含更通用答案的好地方。这是一个常见的问题。您所描述的概念通常被称为“组连接”。 SQL-92 或 SQL-99 中没有标准解决方案。因此,您需要一个特定于供应商的解决方案。

    • MySQL - 使用内置的 GROUP_CONCAT 函数。在您的示例中,您需要这样的内容:
    选择
      o.ID,o.Address,o.OtherDetails,
      GROUP_CONCAT( concat(e.firstname, ' ', e.lastname) ) 作为员工
    从
      员工
      o.org_id=e.org_id 上的内部加入组织o
    按 o.org_id 分组
    
    • PostgreSQL - PostgreSQL 9.0 同样简单,因为 string_agg(expression, delimiter) 是内置的。这里是元素之间的“逗号空格”:
    选择
      o.ID,o.Address,o.OtherDetails,
      STRING_AGG( (e.firstname || ' ' || e.lastname), ', ' ) 作为员工
    从
      员工
      o.org_id=e.org_id 上的内部加入组织o
    按 o.org_id 分组
    

    9.0 之前的 PostgreSQL 允许您使用 CREATE AGGREGATE 定义自己的聚合函数。比 MySQL 稍微多一些工作,但更灵活。有关更多详细信息,请参阅此other post。 (当然 PostgreSQL 9.0 及更高版本也有这个选项。)

    • Oracle - 使用 LISTAGG 的想法相同。

    • MS SQL Server - 使用 STRING_AGG

      的想法相同
    • 后备解决方案 - 在其他数据库技术或上面列出的非常非常旧的技术版本中,您没有这些组连接功能。在这种情况下,创建一个将 org_id 作为其输入并输出连接的员工姓名的存储过程。然后在您的查询中使用此存储过程。此处的其他一些响应包括有关如何编写此类存储过程的一些详细信息。

    选择
      o.ID,o.Address,o.OtherDetails,
      MY_CUSTOM_GROUP_CONCAT_PROCEDURE(o.ID) 作为员工
    从
      组织
    

    【讨论】:

      【解决方案2】:

      由于问题被标记为 MySQL,您应该能够使用 MySQL 特定的解决方案,即 GROUP_CONCAT。例如,

      select Org_ID, Org_Address, Org_OtherDetails,
             GROUP_CONCAT(employees) as Employees
      from  employees a, organization b
      where a.org_id=b.org_id
      group by b.org_id;
      

      【讨论】:

        【解决方案3】:

        在 MS SQL 中你可以这样做:

        create function dbo.table2list (@input int)
        returns varchar(8000)
        as
        BEGIN
        declare @putout varchar(8000)
        set @putout = ''
        select @putout = @putout + ', ' + <employeename>
        from <employeetable>
        where <orgid> = @input
        return @putout
        end
        

        然后做:

        select * from org, dbo.table2list(orgid)
        from <organisationtable>
        

        我认为你也可以使用 COALESCE() 来做到这一点,但不记得我脑海中的语法

        【讨论】:

        • 当然,只要您的所有员工姓名加上逗号和空格的总数达到 8000 - 您就有问题了!
        【解决方案4】:

        如果您使用 Oracle,您可以创建一个 PL/SQL 函数,您可以在查询中使用该函数,该函数接受一个组织 ID 作为输入,并以字符串形式返回属于该组织的所有员工的名字。例如:-

        select
           o.org_id,
           o.org_address,
           o.org_otherdetails,
           org_employees( o.org_id ) as org_employees
        from
           organization o
        

        【讨论】:

          【解决方案5】:

          这一切都取决于。 如果您进行联接,您将获得每一行的所有组织数据。 (每位员工 1 行)。那是有代价的。 如果您执行两个查询。 (Org 和 Emp)具有不同的成本。

          选择你的毒药。

          【讨论】:

            【解决方案6】:

            简短的回答是“不”。

            正如其他答案中所述,有特定于供应商的方法可以实现此结果,但没有纯 SQL 解决方案可以在一个查询中使用。

            很抱歉:(

            大概有一种供应商特定的解决方案适合您?

            【讨论】:

              【解决方案7】:

              这是你可以做的,你有两个选择:

              select *
              FROM
                users u
                LEFT JOIN organizations o ON (u.idorg = o.id);
              

              这样您将获得每行的额外数据 - 您并不真正需要的完整组织信息。

              或者你可以这样做:

              select o.*, group_concat(u.name)
              FROM
                users u
                LEFT JOIN organizations o ON (u.idorg = o.id)
              GROUP BY
                o.id
              

              http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat

              如果你想看ie,第二种方法是适用的。用户名列表“user1, user2, user3”,但不想自己操作字段...

              【讨论】:

                【解决方案8】:

                对于 SQL Server,此项目中的 SQLCLR 聚合受到 MSDN 代码示例的启发,但是它们的性能要好得多,并且允许排序(作为字符串)和在需要时使用备用分隔符。它们提供了几乎与 MySQL 的 GROUP_CONCAT for SQL Server 等效的功能。

                可以在文档中找到 CLR 聚合和 FOR XML 解决方案的优缺点的完整比较:

                http://groupconcat.codeplex.com

                【讨论】:

                  【解决方案9】:

                  对于 SQL Server 2017 和 Azure SQL,现在有一个函数 STRING_AGG (Transact-SQL) 可以与 MySQL 媲美:

                  https://docs.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15.

                  SELECT attribute1, STRING_AGG (attribute2, '|') AS Attribute2
                  FROM  table
                  GROUP BY attribute
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-06-26
                    • 2019-09-30
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多