MS SQL Server 中的组连接

Posted

技术标签:

【中文标题】MS SQL Server 中的组连接【英文标题】:Group Concatenate in MS SQL Server 【发布时间】:2014-03-13 16:58:07 【问题描述】:

我有两个表 dbo.Supplier 和 dbo.L_ProductSupplier (AS LPST),对于 LPST 表上的所有产品 ID,我想连接 dbo.Supplier (AS ST) 中的供应商名称,该供应商名称通过 SupplierID 链接到 LPST字段(每个产品可以有多个供应商)

例如查询应该这样:

LPST.ProductID  LPST.SupplierID ST.SupplierName
1                          A    CompanyA
1                          B    CompanyB
1                          C    CompanyC
2                          X    CompanyX
2                          Y    CompanyY
2                          Z    CompanyZ

然后输出:

LPST.ProductID  SupplierName(s)
1               CompanyA / CompanyB /CompanyC
2               CompanyX / CompanyY / CompanyZ

我尝试了以下代码:

SELECT DISTINCT
LPST.ProductId,
STUFF((SELECT ',' + ST.SupplierName
FROM dbo.Supplier AS ST
WHERE LPST.SupplierId=ST.SupplierId
FOR XML PATH('')),1,1,'') AS SupplierNames 
FROM dbo.L_ProductSupplier AS LPST
GROUP BY LPST.ProductId

...但它给出了错误:列 'dbo.L_ProductSupplier.SupplierId' 在选择列表中无效,因为它既不包含在聚合函数或 GROUP BY 子句中。关于如何解决这个问题的任何想法?如果我删除“分组依据”,那么它会在没有串联的情况下报告 LPST 上的每一行。

还有其他方法吗?我听说游标是一种选择,但我是 SQL 新手,不熟悉它们;有人在这种情况下使用过游标吗?

【问题讨论】:

有几种方法可以做到这一点——没有一种特别优雅。有关您的选项的完整列表,请参阅link。我可能会选择FOR XML PATH 选项(根据 KumarHarsh 的回答),因为它最简洁 谢谢詹姆斯,FOR XML PATH 是我走的路线,但我的代码没有达到预期的结果,有什么想法我出错了吗? 【参考方案1】:

怎么样

DECLARE @Supplier TABLE(
    SupplierId INT,
    SupplierName VARCHAR(50)
)

INSERT INTO @Supplier SELECT 1, 'A'
INSERT INTO @Supplier SELECT 2, 'B'

DECLARE @L_ProductSupplier TABLE(
    ProductId INT,
    SupplierId INT
)       

INSERT INTO @L_ProductSupplier SELECT 1, 1
INSERT INTO @L_ProductSupplier SELECT 1, 2


;WITH Vals AS (
        SELECT  LPST.ProductId,
                LPST.SupplierId,
                ST.SupplierName
        FROM    @L_ProductSupplier LPST LEFT JOIN
                @Supplier ST ON LPST.SupplierId = st.SupplierId
)
SELECT  LPST.ProductId,
        STUFF(
                (
                    SELECT ',' + ST.SupplierName
                    FROM Vals AS ST
                    WHERE LPST.ProductId=ST.ProductId
                    FOR XML PATH('')
                ),
                1,
                1,
                ''
            ) AS SupplierNames 
FROM    Vals AS LPST
GROUP BY    LPST.ProductId

SQL Fiddle DEMO

【讨论】:

感谢 asstander,如果有 200 个公司名称并且我不知道哪些对应于哪些产品,这会起作用吗?【参考方案2】:
Declare @t table (ProductID int,  SupplierID varchar(1),SupplierName varchar(50))
insert into @t
select 1 ,                         'A'  ,  'CompanyA' union all
select 1                          , 'B'   , 'CompanyB' union all
select 1                         , 'C'   , 'CompanyC' union all
select 2                         , 'X'   , 'CompanyX' union all
select 2                         , 'Y'   , 'CompanyY' union all
select 2                         , 'Z'   , 'CompanyZ'

select distinct b.ProductID,stuff((select '/'+a.SupplierName from @t a where a.ProductID=b.ProductID FOR XML path('')),1,1,'')
from @t b 

【讨论】:

谢谢 KumarHarsh... ABCXYZ 只是为了演示,如果有 200 个公司名称,我不知道它们是什么? @user3309874,只要你想根据productid连接供应商名称,你必须提供真实的场景数据。200公司名称无关紧要。告诉我它赢得了哪些样本数据不工作

以上是关于MS SQL Server 中的组连接的主要内容,如果未能解决你的问题,请参考以下文章

linux系统可以使用哪些.so文件对应windows中的.dll文件来连接php到ms sql server

为啥 MS-Access 中的 Teradata 查询比 SQL Server 更快

除非我停止任何本地 SQL Server 实例,否则 Docker、MS SQL Server、SMMS 无法连接

SQL Server 查找包含的组

Debezium MS SQL Server 连接器问题

ms sql server中where子句中的if else条件