如何基于关系获得针对一条记录的多条记录?

时间:2008-09-19 14:33:56

标签: mysql sql database

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

Org_ID      Org_Address    Org_OtherDetails    Employess

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

9 个答案:

答案 0 :(得分:18)

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

  • MySQL - 可能是最简单的解决方案。使用内置的GROUP_CONCAT函数。在你的例子中你会想要这样的东西:
select 
  o.ID, o.Address, o.OtherDetails,
  GROUP_CONCAT( concat(e.firstname, ' ', e.lastname) ) as Employees
from 
  employees e 
  inner join organization o on o.org_id=e.org_id
group by o.org_id
  • PostgreSQL - 编辑: PostgreSQL 9.0现在同样简单,因为string_agg(表达式,分隔符)是内置的。这里是元素之间的'逗号空间':
select 
  o.ID, o.Address, o.OtherDetails,
  STRING_AGG( (e.firstname || ' ' || e.lastname), ', ' ) as Employees
from 
  employees e 
  inner join organization o on o.org_id=e.org_id
group by o.org_id

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

  • Oracle& MS SQL Server - 创建一个存储过程,该过程将org_id作为其输入并输出连接的员工姓名。然后在查询中使用此存储过程。这里的一些其他响应包括有关如何编写这些存储过程的一些细节。
select 
  o.ID, o.Address, o.OtherDetails,
  MY_CUSTOM_GROUP_CONCAT_PROCEDURE( o.ID ) as Employees
from 
  organization o
  • 其他DBMS技术 - 存储过程路由最有可能。也许其他人可以通过更多技术特定的答案来更新这个答案。

答案 1 :(得分:3)

由于问题被标记为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;

答案 2 :(得分:2)

在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()来做,但不记得我头脑中的语法

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

一切都取决于。 如果您进行连接,则会获得每一行的所有组织数据。 (每位员工1排)。这有成本。 如果你做两个查询。 (Org和Emp)有不同的成本。

选择你的毒药。

答案 5 :(得分:0)

简短的回答是“不”。

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

抱歉:(

据推测,某个供应商特定的解决方案适合您?

答案 6 :(得分:0)

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

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”,但不想对字段本身进行操作...

答案 7 :(得分:0)

对于SQL Server SQLCLR此项目中的聚合受MSDN代码示例的启发,但它们执行得更好,并允许排序(如字符串)和备用分隔符(如果需要)。它们为MySQL的SQL Server GROUP_CONCAT提供几乎等效功能。

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

http://groupconcat.codeplex.com

答案 8 :(得分:0)

对于 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