在SQL Server中跨多个行分别串联多个列

时间:2018-10-17 20:34:23

标签: sql-server tsql

我需要在两个表之间联接的SQL Server的多行数据中分别串联两列。

例如,我有一个“关联”表和“市场”表,如下所示”

Association:

user_id |  role_id  | market_id
-------------------------------
1       |     a     |     1
1       |     a     |     2
2       |     c     |     3
2       |     c     |     4
2       |     c     |     5

Market:

market_id | market_name
-----------------------
1         | Arizona
2         | Utah
3         | Indiana
4         | Illinois
5         | Kentucky

我需要将Association表中的market_id与每个用户ID合并为一个值,并从Market表中引入合并后的市场名称,并且期望的输出如下所示:

user_id |  role_id  |  market_ids   | market_names
--------------------------------------------------
1       |     a     |     1,2       | Arizona,Utah
2       |     c     |    3,4,5      | Indiana,Illinois,Kentucky

现在,我能够使用以下SQL成功连接市场ID,但仍然可以为每个市场获得多行数据:

SELECT DISTINCT
    a.user_id,
    a.role_id,
    SUBSTRING(
        (
            SELECT DISTINCT ', ' + market_id  AS [text()]
            FROM Association aa
            WHERE a.user_id = aa.user_id
            FOR XML PATH ('')
        ), 2, 1000) [market_ids],
        SUBSTRING(
        (
            SELECT DISTINCT ', ' + market_name  AS [text()]
            FROM Market bb
            WHERE a.market_id = bb.market_id
            FOR XML PATH ('')
        ), 2, 1000) [Market Name]
FROM
    Association a
    INNER JOIN
    Market b
        ON a.market_id = d.market_id

关于如何实现第二级连接的任何想法?

2 个答案:

答案 0 :(得分:2)

具有Row_Number()来保持演示顺序的CTE应该可以解决问题

示例

;with cte as (
    Select A.*
          ,B.Market_Name
          ,RN = Row_Number() over (Partition By user_id,role_id order by a.market_id)
     From   Association A
     Join   Market B on A.market_id=B.market_id
)
Select Distinct
       user_id
      ,role_id
      ,market_ids   = stuff((Select concat(',',market_id  ) From cte Where user_id=A.user_id and role_id=A.role_id Order By RN For XML Path ('')),1,1,'')
      ,market_names = stuff((Select concat(',',market_name) From cte Where user_id=A.user_id and role_id=A.role_id Order By RN For XML Path ('')),1,1,'')
 From  cte A

返回

user_id role_id market_ids  market_names
1       a       1,2         Arizona,Utah
2       c       3,4,5       Indiana,Illinois,Kentucky

答案 1 :(得分:0)

Stuff()相比,我更喜欢使用Substring()。无论如何,基本上对于市场名称,您应该在您的子查询中进行关联联接,然后在用户ID上联接两个关联表。尝试这样的事情:

SELECT DISTINCT
a.user_id,
    a.role_id,
    STUFF(
        (
            SELECT DISTINCT ', ' + cast(market_id  as varchar(25))
            FROM Association aa
            WHERE a.[user_id] = aa.[user_id]
            FOR XML PATH ('')
        ), 1, 1,'') [market_ids],
        STUFF(
        (
            SELECT DISTINCT ', ' + market_name 
            FROM Market bb
          Inner join Association aaa on aaa.market_id = bb.market_id
            WHERE a.user_id = aaa.user_id
            FOR XML PATH ('')
        ), 1, 1,'') [Market Name]
FROM  Association a 

您的原始查询可以写为:

SELECT DISTINCT
    a.[user_id],
    a.role_id,
    SUBSTRING(
        (
            SELECT DISTINCT ', ' + cast(market_id  as varchar(25)) AS [text()]
            FROM #Association aa
            WHERE a.[user_id] = aa.[user_id]
            FOR XML PATH ('')
        ), 2, 1000) [market_ids],
        SUBSTRING(
        (
            SELECT DISTINCT ', ' + market_name  AS [text()]
            FROM #Market bb
          INNER JOIN #Association aaa on aaa.market_id = bb.market_id
            WHERE a.user_id = aaa.user_id
            FOR XML PATH ('')
        ), 2, 1000) [Market Name]
FROM  #Association a