具有相同ID的Merge / Concat列,而不使用' For XML Path

时间:2017-04-18 00:40:56

标签: sql sql-server

我有一个包含以下数据的表:

Name | UserType | Locations
-----------------------
Mike | A        | China
Mike | A        | Australia
Mike | B        | Mexico
Mike | B        | Russia
John | A        | Japan
John | A        | China

我想要的输出如下:

Name | UserType | Locations
-----------------------
Mike | A        | China, Australia
Mike | B        | Mexico, Russia
John | A        | Japan, China

目前,我可以通过使用' FOR XML PATH'来实现这一目标。像这样:

SELECT Name, UserType, Location = 
      STUFF((SELECT DISTINCT ', ' + location
           from @MyTable b
           where b.name = a.name
           and b.UserType = a.UserType
           FOR XML PATH('')), 1, 2, '')
FROM @MyTable a

@ MyTable是我从中检索数据的表。

我无法使用此查询的原因是因为我正在处理至少约500,000条记录并且需要很长时间才能完成(我必须选择前100行来检查它是否正常工作,因为我认为我的系统已经挂了)。

我一直在寻找,我能找到的所有sqlserver都是这个xml路径的东西。 是否有可能在不使用xml的情况下在sql中实现我想要的东西?或者我应该只获取所有记录并在代码中执行此操作?对于任何想知道这个输出的人都会进入一个excel生成的报告,然后客户端下载。

4 个答案:

答案 0 :(得分:0)

首先,写下这样的查询:

SELECT Name, UserType, 
       STUFF((SELECT DISTINCT ', ' + location
              FROM @MyTable b
              WHERE b.name = a.name AND b.UserType = a.UserType
              FOR XML PATH('')
             ), 1, 2, ''
            ) as locations
FROM (SELECT DISTINCT Name, UserType FROM @MyTable) a;

这会将工作量减少到每Name / UserTYpe对仅一个子查询调用。

接下来,您可以在@MyTable(name, UserType, location)上建立索引。您可以通过将组合声明为唯一键或主键来完成此操作。或者,您可以使用临时表并显式添加索引。

答案 1 :(得分:0)

除非你没有提供真正的表结构和样本数据,否则没有必要探讨“为什么查询很慢”。

i)如果可能的话,你可以改变你的数据库设计。

ii)为什么你一次只能查询5 00,000条记录呢 使用distinct?

试试这个,

declare @t table(Name varchar(50), UserType varchar(50), Locations varchar(50))
insert into @t VALUES
-----------------------
('Mike','A','China'    )
,('Mike','A','Australia')
,('Mike','B','Mexico'   )
,('Mike','B','Russia'   )
,('John','A','Japan'    )
,('John','A','China'    )

;with CTE as
(
 select * 
 ,ROW_NUMBER()over(PARTITION by name,usertype order by name)rn
 from @t

)

select name ,usertype
,stuff((select ','+ Locations from cte c1 where c1.name=c.name 
and c.usertype=c1.usertype  for xml path('')),1,1,'')
Locations
from cte c
where rn=1

答案 2 :(得分:0)

尝试以下查询:

  DECLARE @MyTable TABLE ( Name VARCHAR(100), UserType VARCHAR(100), 
      Locations VARCHAR(100) )

  INSERT INTO @MyTable ( Name , UserType , Locations  ) 
  SELECT 'Mike','A','China' UNION ALL
  SELECT 'Mike','A','Australia' UNION ALL
  SELECT 'Mike','B','Mexico' UNION ALL
  SELECT 'Mike','B','Russia' UNION ALL
  SELECT 'John','A','Japan' UNION ALL
  SELECT 'John','A','China' 

  SELECT Name , UserType , 
        STUFF (( SELECT  ',' + Locations FROM @MyTable I WHERE I.Name = 
                 O.Name AND I.UserType = O.UserType FOR XML PATH('')) 
              ,1,1,'')
  FROM @MyTable O
  GROUP BY Name , UserType

在查询下方没有使用XML:

  ;WITH CTE ( UniqId , _Id , _Name , _UserType , _Locations) AS
   (
      SELECT 1 , Id , Name , UserType , Locations 
      FROM @MyTable
      UNION ALL 
      SELECT UniqId + 1 , _Id + 1 , _Name , _UserType , _Locations + ',' + 
             Locations
      FROM CTE
      JOIN @MyTable ON _Name = Name AND _UserType = UserType AND _Id < Id 
    )


    SELECT CTE._Name Name, CTE._UserType UserType, CTE._Locations Locations
    FROM CTE
    JOIN 
    (
        SELECT MAX(UniqId) _UniqId ,_Name , _UserType 
        FROM CTE
        GROUP BY _Name , _UserType
    ) A ON _UniqId = UniqId AND A._Name  = CTE._Name AND A._UserType = 
        CTE._UserType  

答案 3 :(得分:0)

我们可以在CLR Aggregate函数的帮助下不使用'For XML Path'来实现这一目标 试试这个链接clickHere