60

我有 3 个表称为:

  • 应用程序(ID、名称)
  • 资源(id,名称)
  • 应用程序资源(id、app_id、resource_id)

我想在 GUI 上显示所有资源名称的表。在每一行的一个单元格中,我想列出该资源的所有应用程序(逗号分隔)。

所以问题是,在 SQL 中执行此操作的最佳方法是什么,因为我需要获取所有资源并且还需要获取每个资源的所有应用程序?

我是否首先运行 select * from resources 然后循环遍历每个资源并对每个资源执行单独的查询以获取该资源的应用程序列表?

有没有办法在一个查询中做到这一点?

4

11 回答 11

133

MySQL

  SELECT r.name,
         GROUP_CONCAT(a.name SEPARATOR ',')
    FROM RESOURCES r
    JOIN APPLICATIONSRESOURCES ar ON ar.resource_id = r.id
    JOIN APPLICATIONS a ON a.id = ar.app_id
GROUP BY r.name

SQL Server (2005+)

SELECT r.name,
       STUFF((SELECT ',' + a.name
               FROM APPLICATIONS a
               JOIN APPLICATIONRESOURCES ar ON ar.app_id = a.id
              WHERE ar.resource_id = r.id
           GROUP BY a.name
            FOR XML PATH(''), TYPE).value('text()[1]','NVARCHAR(max)'), 1, LEN(','), '')
 FROM RESOURCES r

SQL Server (2017+)

  SELECT r.name,
         STRING_AGG(a.name, ',')
    FROM RESOURCES r
    JOIN APPLICATIONSRESOURCES ar ON ar.resource_id = r.id
    JOIN APPLICATIONS a ON a.id = ar.app_id
GROUP BY r.name

甲骨文

我建议阅读 Oracle 中的字符串聚合/连接

于 2009-11-30T05:55:11.643 回答
34

笔记:

不推荐使用此方法,因为它会给出不正确或不确定的结果。
这已记录在StackOverflowDBA上

使用 COALESCE 在 SQL Server 中构建逗号分隔字符串
http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string

例子:

DECLARE @EmployeeList varchar(100)

SELECT @EmployeeList = COALESCE(@EmployeeList + ', ', '') + 
   CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1

SELECT @EmployeeList
于 2009-11-30T05:38:52.940 回答
11

我不知道是否有任何解决方案可以以与数据库无关的方式执行此操作,因为您很可能需要某种形式的字符串操作,而且这些操作通常在供应商之间有所不同。

对于 SQL Server 2005 及更高版本,您可以使用:

SELECT
     r.ID, r.Name,
     Resources = STUFF(
       (SELECT ','+a.Name
        FROM dbo.Applications a
        INNER JOIN dbo.ApplicationsResources ar ON ar.app_id = a.id
        WHERE ar.resource_id = r.id
        FOR XML PATH('')), 1, 1, '')
FROM
     dbo.Resources r

它使用 SQL Server 2005FOR XML PATH构造将子项(给定资源的应用程序)列为逗号分隔的列表。

马克

于 2009-11-30T05:51:54.207 回答
5

我相信你想要的是:

SELECT ItemName, GROUP_CONCAT(DepartmentId) FROM table_name GROUP BY ItemName

如果你使用 MySQL

参考

于 2010-06-21T19:22:03.373 回答
5

假设 SQL Server:

表结构:

CREATE TABLE [dbo].[item_dept](
    [ItemName] char(20) NULL,
    [DepartmentID] int NULL   
)

询问:

SELECT ItemName,
       STUFF((SELECT ',' + rtrim(convert(char(10),DepartmentID))
        FROM   item_dept b
        WHERE  a.ItemName = b.ItemName
        FOR XML PATH('')),1,1,'') DepartmentID
FROM   item_dept a
GROUP BY ItemName

结果:

ItemName    DepartmentID
item1       21,13,9,36
item2       4,9,44
于 2010-06-21T19:25:22.633 回答
4

SQL Server 的下一个版本开始,您将能够做到

SELECT r.name,
       STRING_AGG(a.name, ',')
FROM   RESOURCES r
       JOIN APPLICATIONSRESOURCES ar
         ON ar.resource_id = r.id
       JOIN APPLICATIONS a
         ON a.id = ar.app_id
GROUP  BY r.name 

对于该产品的早期版本,有很多不同的方法来解决这个问题。文章中对它们进行了很好的回顾:在 Transact-SQL 中连接行值

  • 当项目数未知时连接值

    • 递归 CTE 方法
    • 黑盒 XML 方法
    • 使用公共语言运行时
    • 带有递归的标量 UDF
    • 带有 WHILE 循环的表值 UDF
    • 动态 SQL
    • 光标方法
  • 不可靠的方法

    • 带有 t-SQL 更新扩展的标量 UDF
    • SELECT 中具有变量连接的标量 UDF
于 2010-06-25T20:35:01.490 回答
4

我想我们可以写成下面的方式来检索(下面的代码只是一个例子,请根据需要修改):

Create FUNCTION dbo.ufnGetEmployeeMultiple(@DepartmentID int)
RETURNS VARCHAR(1000) AS

BEGIN

DECLARE @Employeelist varchar(1000)

SELECT @Employeelist = COALESCE(@Employeelist + ', ', '') + E.LoginID
FROM humanresources.Employee E

Left JOIN humanresources.EmployeeDepartmentHistory H ON
E.BusinessEntityID = H.BusinessEntityID

INNER JOIN HumanResources.Department D ON
H.DepartmentID = D.DepartmentID

Where H.DepartmentID = @DepartmentID

Return @Employeelist

END

SELECT D.name as Department, dbo.ufnGetEmployeeMultiple (D.DepartmentID)as Employees
FROM HumanResources.Department D

SELECT Distinct (D.name) as Department, dbo.ufnGetEmployeeMultiple (D.DepartmentID) as 
Employees
FROM HumanResources.Department D
于 2012-09-25T03:31:31.923 回答
2

MySQL

  SELECT r.name,
         GROUP_CONCAT(a.name SEPARATOR ',')
    FROM RESOURCES r
    JOIN APPLICATIONSRESOURCES ar ON ar.resource_id = r.id
    JOIN APPLICATIONS a ON a.id = ar.app_id
GROUP BY r.name

**


微软 SQL 服务器

SELECT r.name,
       STUFF((SELECT ','+ a.name
               FROM APPLICATIONS a
               JOIN APPLICATIONRESOURCES ar ON ar.app_id = a.id
              WHERE ar.resource_id = r.id
           GROUP BY a.name
            FOR XML PATH(''), TYPE).value('.','VARCHAR(max)'), 1, 1, '')
 FROM RESOURCES r
 GROUP BY deptno;

甲骨文

  SELECT r.name,
         LISTAGG(a.name SEPARATOR ',') WITHIN GROUP (ORDER BY a.name)
  FROM RESOURCES r
        JOIN APPLICATIONSRESOURCES ar ON ar.resource_id = r.id
        JOIN APPLICATIONS a ON a.id = ar.app_id
  GROUP BY r.name;
于 2016-04-20T08:04:41.367 回答
1

要不可知论,请退后并弃船。

Select a.name as a_name, r.name as r_name
  from ApplicationsResource ar, Applications a, Resources r
 where a.id = ar.app_id
   and r.id = ar.resource_id
 order by r.name, a.name;

现在使用您的服务器编程语言连接 a_names 而 r_name 与上次相同。

于 2009-11-30T05:56:40.953 回答
1

这将在 SQL Server 中完成:

DECLARE @listStr VARCHAR(MAX)
SELECT @listStr = COALESCE(@listStr+',' ,'') + Convert(nvarchar(8),DepartmentId)
FROM Table
SELECT @listStr
于 2010-06-21T19:20:12.177 回答
0

没有办法以与 DB 无关的方式来做到这一点。因此,您需要像这样获取整个数据集:

select 
  r.name as ResName, 
  a.name as AppName
from 
  Resouces as r, 
  Applications as a, 
  ApplicationsResources as ar
where
  ar.app_id = a.id 
  and ar.resource_id = r.id

然后在按ResName分组时以编程方式连接AppName

于 2009-11-30T06:03:24.137 回答